Repository: swaggest/rest
Pull request #160 (2023-05-28 08:58:12)

Fix handling of optional uploads
Fixes a bug mentioned in https://github.com/swaggest/rest/discussions/159.

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

| Language  | Files |   Lines    |    Code    | Comments |   Blanks   | Complexity |     Bytes      |
|-----------|-------|------------|------------|----------|------------|------------|----------------|
| Go        | 106   | 7686 (+8)  | 5590 (+4)  | 504      | 1592 (+4)  | 948        | 186.4K (+46B)  |
| Go (test) | 48    | 5495 (+27) | 4236 (+43) | 187      | 1072 (-16) | 180 (-2)   | 152.8K (+734B) |
<!-- Sticky Pull Request CommentLOC -->
github-actions[bot]: ### Go API Changes

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

|          File           |   Function    | Coverage |
|-------------------------|---------------|----------|
| Total                   |               | 80.0%    |
| request/file.go         |               | 100.0%   |
| request/file.go:60      | setFile       | 100.0%   |
| response/encoder.go     |               | 75.0%    |
| response/encoder.go:197 | successStatus | 100.0%   |

</details>

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

|                   File                   | Function | Base Coverage | Current Coverage |
|------------------------------------------|----------|---------------|------------------|
| Total                                    |          | 83.5%         | 83.6% (+0.1%)    |
| github.com/swaggest/rest/request/file.go | setFile  | 78.6%         | 86.2% (+7.6%)    |

</details>
<!-- Sticky Pull Request Commentunit-test -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/swaggest/rest/pull/160?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) Report
> Merging [#160](https://app.codecov.io/gh/swaggest/rest/pull/160?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) (32d13ec) into [master](https://app.codecov.io/gh/swaggest/rest/commit/dee7f9fac2a11960641dbaf11f78524375129e23?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) (dee7f9f) will **increase** coverage by `0.18%`.
> The diff coverage is `66.66%`.

```diff
@@            Coverage Diff             @@
##           master     #160      +/-   ##
==========================================
+ Coverage   77.79%   77.98%   +0.18%     
==========================================
  Files          28       28              
  Lines        1608     1608              
==========================================
+ Hits         1251     1254       +3     
+ Misses        235      233       -2     
+ Partials      122      121       -1     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `77.98% <66.66%> (+0.18%)` | :arrow_up: |

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.

| [Impacted Files](https://app.codecov.io/gh/swaggest/rest/pull/160?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) | Coverage Δ | |
|---|---|---|
| [response/encoder.go](https://app.codecov.io/gh/swaggest/rest/pull/160?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest#diff-cmVzcG9uc2UvZW5jb2Rlci5nbw==) | `68.06% <50.00%> (+0.28%)` | :arrow_up: |
| [request/file.go](https://app.codecov.io/gh/swaggest/rest/pull/160?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest#diff-cmVxdWVzdC9maWxlLmdv) | `70.45% <100.00%> (+5.33%)` | :arrow_up: |

: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)

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

```
name                                    old time/op    new time/op    delta
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-2    1.66µs ± 8%    1.64µs ± 5%    ~     (p=0.699 n=6+6)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                           832ns ± 1%     841ns ± 5%    ~     (p=0.537 n=5+6)
DecoderFunc_Decode-2                      2.38µs ± 1%    2.38µs ± 0%    ~     (p=0.802 n=5+5)
Decoder_Decode_json-2                     26.5µs ± 1%    26.0µs ± 1%  -1.70%  (p=0.002 n=6+6)
Decoder_Decode_queryObject-2              5.87µs ± 1%    5.82µs ± 2%    ~     (p=0.394 n=6+6)
Decoder_Decode_jsonParam-2                2.12µs ± 1%    2.18µs ± 2%  +3.00%  (p=0.004 n=6+6)
DecoderFactory_SetDecoderFunc-2           2.01µs ± 1%    1.99µs ± 2%    ~     (p=0.288 n=6+6)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                              13.5µs ± 2%    13.4µs ± 3%    ~     (p=0.394 n=6+6)
Middleware_control-2                      4.32µs ± 7%    4.34µs ± 3%    ~     (p=0.937 n=6+6)

name                                    old alloc/op   new alloc/op   delta
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-2    2.46kB ± 0%    2.46kB ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                            440B ± 0%      440B ± 0%    ~     (all equal)
DecoderFunc_Decode-2                      1.51kB ± 0%    1.51kB ± 0%    ~     (all equal)
Decoder_Decode_json-2                     12.2kB ± 0%    12.2kB ± 0%    ~     (all equal)
Decoder_Decode_queryObject-2              2.00kB ± 0%    2.00kB ± 0%    ~     (all equal)
Decoder_Decode_jsonParam-2                  736B ± 0%      736B ± 0%    ~     (all equal)
DecoderFactory_SetDecoderFunc-2           1.02kB ± 0%    1.02kB ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                              1.17kB ± 6%    1.15kB ± 6%    ~     (p=0.548 n=6+6)
Middleware_control-2                      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-2      8.00 ± 0%      8.00 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                            4.00 ± 0%      4.00 ± 0%    ~     (all equal)
DecoderFunc_Decode-2                        12.0 ± 0%      12.0 ± 0%    ~     (all equal)
Decoder_Decode_json-2                        177 ± 0%       177 ± 0%    ~     (all equal)
Decoder_Decode_queryObject-2                36.0 ± 0%      36.0 ± 0%    ~     (all equal)
Decoder_Decode_jsonParam-2                  13.0 ± 0%      13.0 ± 0%    ~     (all equal)
DecoderFactory_SetDecoderFunc-2             16.0 ± 0%      16.0 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                                11.0 ± 0%      11.0 ± 0%    ~     (all equal)
Middleware_control-2                        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-2  1.64µs ± 5%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                         841ns ± 5%
DecoderFunc_Decode-2                    2.38µs ± 0%
Decoder_Decode_json-2                   26.0µs ± 1%
Decoder_Decode_queryObject-2            5.82µs ± 2%
Decoder_Decode_jsonParam-2              2.18µs ± 2%
DecoderFactory_SetDecoderFunc-2         1.99µs ± 2%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                            13.4µs ± 3%
Middleware_control-2                    4.34µs ± 3%

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

name                                    allocs/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-2    8.00 ± 0%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                          4.00 ± 0%
DecoderFunc_Decode-2                      12.0 ± 0%
Decoder_Decode_json-2                      177 ± 0%
Decoder_Decode_queryObject-2              36.0 ± 0%
Decoder_Decode_jsonParam-2                13.0 ± 0%
DecoderFactory_SetDecoderFunc-2           16.0 ± 0%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                              11.0 ± 0%
Middleware_control-2                      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-2                33.0µs ± 4%    39.2µs ±24%  +18.84%  (p=0.008 n=5+5)
_directGzipHead-2            33.5µs ±14%    36.1µs ± 3%     ~     (p=0.151 n=5+5)
_noDirectGzip-2               162µs ± 4%     176µs ± 1%   +8.10%  (p=0.008 n=5+5)
_directGzip_decode-2          573µs ± 6%     612µs ± 2%   +6.81%  (p=0.032 n=5+5)
_noDirectGzip_decode-2        168µs ± 8%     178µs ± 4%     ~     (p=0.095 n=5+5)
_jsonBody-2                  74.8µs ± 7%    76.7µs ± 4%     ~     (p=0.222 n=5+5)
_jsonBodyValidation-2        79.0µs ± 8%    85.3µs ± 2%   +7.98%  (p=0.016 n=5+5)
_outputHeaders-2             36.5µs ±13%    38.0µs ± 2%     ~     (p=0.151 n=5+5)
_requestResponseMapping-2    69.0µs ± 6%    72.6µs ± 2%     ~     (p=0.056 n=5+5)
_validation-2                75.8µs ± 8%    79.7µs ± 2%     ~     (p=0.151 n=5+5)
_noValidation-2              55.0µs ± 3%    60.0µs ± 4%   +9.11%  (p=0.008 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                36.8µs ±21%    39.7µs ± 5%     ~     (p=0.151 n=5+5)
_directGzipHead-2            35.0µs ± 7%    39.0µs ± 5%  +11.31%  (p=0.016 n=5+5)
_noDirectGzip-2               176µs ± 4%     181µs ± 4%     ~     (p=0.310 n=5+5)
_directGzip_decode-2          628µs ± 3%     626µs ± 2%     ~     (p=0.841 n=5+5)
_noDirectGzip_decode-2        171µs ± 3%     180µs ± 3%   +5.56%  (p=0.016 n=5+5)
_htmlResponse-2              63.8µs ± 3%    65.8µs ± 1%   +3.06%  (p=0.032 n=5+5)
_jsonBodyManual-2            47.0µs ± 5%    47.8µs ± 1%     ~     (p=0.421 n=5+5)
_jsonBody-2                  69.4µs ± 3%    74.1µs ± 4%   +6.76%  (p=0.008 n=5+5)
_jsonBodyValidation-2        87.1µs ± 4%    95.1µs ± 5%   +9.16%  (p=0.008 n=5+5)
_outputHeaders-2             65.1µs ± 4%    69.8µs ±11%   +7.37%  (p=0.032 n=5+5)
_requestResponseMapping-2    75.3µs ± 6%    82.2µs ± 3%   +9.09%  (p=0.016 n=5+5)
_validation-2                77.3µs ± 1%    88.9µs ± 3%  +15.06%  (p=0.008 n=5+5)
_noValidation-2              58.8µs ± 4%    61.3µs ± 4%   +4.17%  (p=0.032 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2               44.2µs ±13%    45.4µs ±12%     ~     (p=0.421 n=5+5)
_ok-2                        43.8µs ± 4%    44.7µs ± 2%     ~     (p=0.222 n=5+5)
_invalidBody-2               66.5µs ± 6%    64.5µs ± 3%     ~     (p=0.222 n=5+5)

name                       old 50%:ms     new 50%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2                  1.55 ± 3%      1.74 ±11%  +11.86%  (p=0.008 n=5+5)
_directGzipHead-2              1.52 ± 2%      1.74 ± 6%  +14.67%  (p=0.008 n=5+5)
_noDirectGzip-2                7.67 ± 5%      8.46 ± 6%  +10.28%  (p=0.008 n=5+5)
_directGzip_decode-2           22.8 ±13%      23.7 ± 6%     ~     (p=0.421 n=5+5)
_noDirectGzip_decode-2         7.78 ±10%      8.41 ± 4%     ~     (p=0.095 n=5+5)
_jsonBody-2                    3.31 ± 5%      3.47 ± 3%   +4.90%  (p=0.008 n=5+5)
_jsonBodyValidation-2          3.59 ± 9%      3.92 ± 4%   +9.05%  (p=0.048 n=5+5)
_outputHeaders-2               1.65 ± 5%      1.75 ± 7%     ~     (p=0.056 n=5+5)
_requestResponseMapping-2      3.11 ± 8%      3.21 ± 1%     ~     (p=0.151 n=5+5)
_validation-2                  3.39 ± 4%      3.62 ± 4%   +6.51%  (p=0.032 n=5+5)
_noValidation-2                2.46 ± 8%      2.81 ± 7%  +14.45%  (p=0.016 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                  1.71 ±14%      1.86 ± 6%     ~     (p=0.095 n=5+5)
_directGzipHead-2              1.65 ± 7%      1.87 ± 9%  +13.82%  (p=0.032 n=5+5)
_noDirectGzip-2                8.00 ± 3%      8.39 ±10%     ~     (p=0.151 n=5+5)
_directGzip_decode-2           23.9 ± 6%      23.6 ± 9%     ~     (p=1.000 n=5+5)
_noDirectGzip_decode-2         8.02 ± 9%      8.33 ± 5%     ~     (p=0.310 n=5+5)
_htmlResponse-2                3.01 ± 7%      2.95 ± 3%     ~     (p=0.690 n=5+5)
_jsonBodyManual-2              2.28 ± 6%      2.25 ± 6%     ~     (p=1.000 n=5+5)
_jsonBody-2                    3.14 ± 3%      3.37 ± 6%   +7.30%  (p=0.016 n=5+5)
_jsonBodyValidation-2          3.93 ± 5%      4.28 ± 8%   +8.88%  (p=0.008 n=5+5)
_outputHeaders-2               2.87 ± 9%      3.08 ± 6%     ~     (p=0.056 n=5+5)
_requestResponseMapping-2      3.35 ± 5%      3.73 ± 4%  +11.41%  (p=0.008 n=5+5)
_validation-2                  3.44 ± 7%      3.92 ± 5%  +13.97%  (p=0.008 n=5+5)
_noValidation-2                2.70 ± 9%      2.77 ± 9%     ~     (p=1.000 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                 2.11 ±11%      2.14 ± 4%     ~     (p=0.310 n=5+5)
_ok-2                          2.08 ± 3%      2.13 ± 5%     ~     (p=0.310 n=5+5)
_invalidBody-2                 2.97 ± 3%      2.96 ± 6%     ~     (p=1.000 n=5+5)

name                       old 90%:ms     new 90%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2                  2.79 ± 6%      3.34 ±16%  +19.80%  (p=0.008 n=5+5)
_directGzipHead-2              2.80 ±11%      2.99 ± 1%     ~     (p=0.127 n=5+5)
_noDirectGzip-2                14.1 ± 1%      15.9 ± 3%  +12.30%  (p=0.008 n=5+5)
_directGzip_decode-2           47.9 ± 6%      50.9 ± 6%     ~     (p=0.095 n=5+5)
_noDirectGzip_decode-2         14.8 ±11%      16.2 ± 6%     ~     (p=0.056 n=5+5)
_jsonBody-2                    6.71 ± 5%      6.64 ± 2%     ~     (p=0.841 n=5+5)
_jsonBodyValidation-2          6.89 ± 4%      7.37 ± 6%     ~     (p=0.056 n=5+5)
_outputHeaders-2               3.16 ±15%      3.30 ± 6%     ~     (p=0.310 n=5+5)
_requestResponseMapping-2      5.99 ± 7%      6.40 ± 4%     ~     (p=0.151 n=5+5)
_validation-2                  6.72 ±14%      7.16 ± 7%     ~     (p=0.151 n=5+5)
_noValidation-2                4.85 ± 4%      5.28 ± 5%   +8.89%  (p=0.008 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                  3.22 ±20%      3.38 ± 8%     ~     (p=0.151 n=5+5)
_directGzipHead-2              3.02 ± 8%      3.31 ± 9%   +9.39%  (p=0.040 n=5+5)
_noDirectGzip-2                16.0 ±12%      17.1 ± 7%     ~     (p=0.310 n=5+5)
_directGzip_decode-2           52.0 ± 8%      53.8 ± 4%     ~     (p=0.421 n=5+5)
_noDirectGzip_decode-2         15.5 ± 5%      16.4 ± 6%     ~     (p=0.056 n=5+5)
_htmlResponse-2                5.56 ± 4%      5.81 ± 5%     ~     (p=0.151 n=5+5)
_jsonBodyManual-2              3.92 ± 3%      4.02 ± 3%     ~     (p=0.421 n=5+5)
_jsonBody-2                    6.35 ± 6%      6.66 ± 8%     ~     (p=0.095 n=5+5)
_jsonBodyValidation-2          7.78 ±11%      8.40 ± 6%     ~     (p=0.151 n=5+5)
_outputHeaders-2               5.87 ± 5%      6.43 ± 9%     ~     (p=0.056 n=5+5)
_requestResponseMapping-2      6.76 ± 6%      7.59 ± 2%  +12.18%  (p=0.008 n=5+5)
_validation-2                  6.96 ± 4%      7.93 ± 4%  +13.93%  (p=0.008 n=5+5)
_noValidation-2                5.38 ± 9%      5.56 ± 6%     ~     (p=0.310 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                 3.81 ±16%      3.87 ± 9%     ~     (p=0.802 n=5+5)
_ok-2                          3.76 ± 4%      3.83 ± 4%     ~     (p=0.310 n=5+5)
_invalidBody-2                 6.13 ± 9%      5.96 ± 2%     ~     (p=0.548 n=5+5)

name                       old 99%:ms     new 99%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2                  4.78 ±13%      5.28 ± 6%     ~     (p=0.111 n=5+4)
_directGzipHead-2              4.58 ± 8%      4.96 ±11%     ~     (p=0.190 n=4+5)
_noDirectGzip-2                21.5 ± 6%      21.7 ± 4%     ~     (p=0.548 n=5+5)
_directGzip_decode-2           78.1 ±16%      84.7 ±11%     ~     (p=0.310 n=5+5)
_noDirectGzip_decode-2         21.7 ± 6%      21.9 ± 4%     ~     (p=1.000 n=5+5)
_jsonBody-2                    10.9 ±17%      10.5 ± 8%     ~     (p=0.841 n=5+5)
_jsonBodyValidation-2          10.6 ±14%      11.1 ±13%     ~     (p=0.421 n=5+5)
_outputHeaders-2               5.67 ± 6%      5.77 ±12%     ~     (p=0.556 n=4+5)
_requestResponseMapping-2      10.5 ±16%      10.5 ± 8%     ~     (p=0.841 n=5+5)
_validation-2                  11.8 ±22%      11.1 ±10%     ~     (p=0.841 n=5+5)
_noValidation-2                8.84 ± 9%      9.22 ±10%     ~     (p=0.310 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                  4.86 ± 8%      6.91 ±48%  +42.23%  (p=0.016 n=4+5)
_directGzipHead-2              4.96 ±14%      6.11 ±19%  +23.24%  (p=0.016 n=5+5)
_noDirectGzip-2                23.2 ± 8%      22.6 ± 8%     ~     (p=0.690 n=5+5)
_directGzip_decode-2           87.5 ±13%      89.8 ± 7%     ~     (p=0.548 n=5+5)
_noDirectGzip_decode-2         22.1 ± 6%      22.9 ± 4%     ~     (p=0.095 n=5+5)
_htmlResponse-2                8.93 ± 1%      9.86 ± 9%  +10.42%  (p=0.016 n=4+5)
_jsonBodyManual-2              7.33 ±12%      7.14 ± 7%     ~     (p=0.690 n=5+5)
_jsonBody-2                    10.5 ±21%      10.7 ± 7%     ~     (p=0.690 n=5+5)
_jsonBodyValidation-2          11.9 ± 9%      12.6 ±10%     ~     (p=0.222 n=5+5)
_outputHeaders-2               10.4 ±12%      10.9 ±45%     ~     (p=0.690 n=5+5)
_requestResponseMapping-2      11.3 ±19%      12.6 ±12%     ~     (p=0.056 n=5+5)
_validation-2                  10.8 ± 5%      12.5 ±14%  +16.41%  (p=0.032 n=5+5)
_noValidation-2                8.97 ±17%      9.46 ±13%     ~     (p=0.421 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                 5.66 ± 6%      5.80 ± 3%     ~     (p=0.486 n=4+4)
_ok-2                          6.47 ±22%      6.25 ± 5%     ~     (p=1.000 n=5+5)
_invalidBody-2                 10.6 ±13%      10.0 ± 9%     ~     (p=0.222 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-2                  8.41 ±20%     10.44 ±81%     ~     (p=0.690 n=5+5)
_directGzipHead-2              12.2 ±75%       8.1 ±14%     ~     (p=0.548 n=5+5)
_noDirectGzip-2                26.6 ±10%      25.5 ± 8%     ~     (p=0.310 n=5+5)
_directGzip_decode-2            104 ±18%       107 ± 8%     ~     (p=0.690 n=5+5)
_noDirectGzip_decode-2         24.8 ± 5%      25.8 ±12%     ~     (p=0.421 n=5+5)
_jsonBody-2                    16.4 ±35%      15.9 ±27%     ~     (p=0.841 n=5+5)
_jsonBodyValidation-2          16.2 ±35%      17.1 ±42%     ~     (p=1.000 n=5+5)
_outputHeaders-2               14.9 ±46%      10.2 ±16%     ~     (p=0.095 n=5+5)
_requestResponseMapping-2      17.4 ±11%      18.5 ±23%     ~     (p=0.548 n=5+5)
_validation-2                  18.9 ±25%      16.1 ±30%     ~     (p=0.421 n=5+5)
_noValidation-2                16.9 ±29%      14.7 ±29%     ~     (p=0.310 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                  10.6 ±53%      13.1 ±74%     ~     (p=0.548 n=5+5)
_directGzipHead-2              8.97 ±30%      9.94 ±42%     ~     (p=0.690 n=5+5)
_noDirectGzip-2                28.9 ±18%      29.4 ±13%     ~     (p=1.000 n=5+5)
_directGzip_decode-2            111 ±10%       119 ±11%     ~     (p=0.222 n=5+5)
_noDirectGzip_decode-2         29.0 ±34%      26.7 ±11%     ~     (p=0.841 n=5+5)
_htmlResponse-2                12.4 ±15%      14.0 ±21%     ~     (p=0.151 n=5+5)
_jsonBodyManual-2              12.6 ±27%      12.2 ±45%     ~     (p=1.000 n=5+5)
_jsonBody-2                    16.3 ±29%      16.1 ±18%     ~     (p=1.000 n=5+5)
_jsonBodyValidation-2          16.8 ± 8%      21.5 ±36%     ~     (p=0.151 n=5+5)
_outputHeaders-2               15.9 ±16%      16.3 ±37%     ~     (p=1.000 n=5+5)
_requestResponseMapping-2      18.6 ±66%      17.7 ±33%     ~     (p=1.000 n=5+5)
_validation-2                  16.1 ±16%      18.1 ±27%     ~     (p=0.310 n=5+5)
_noValidation-2                14.2 ±30%      15.4 ±41%     ~     (p=1.000 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                 11.1 ±44%      11.0 ±80%     ~     (p=0.548 n=5+5)
_ok-2                          11.7 ±42%       9.3 ±20%     ~     (p=0.310 n=5+5)
_invalidBody-2                 17.3 ±70%      16.9 ±89%     ~     (p=0.690 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-2                   630 ± 0%       630 ± 0%     ~     (all equal)
_directGzipHead-2               174 ± 0%       174 ± 0%     ~     (all equal)
_noDirectGzip-2               1.03k ± 0%     1.03k ± 0%     ~     (all equal)
_directGzip_decode-2            630 ± 0%       630 ± 0%     ~     (all equal)
_noDirectGzip_decode-2        1.03k ± 0%     1.03k ± 0%     ~     (all equal)
_jsonBody-2                     199 ± 0%       199 ± 0%     ~     (all equal)
_jsonBodyValidation-2           185 ± 0%       185 ± 0%     ~     (all equal)
_outputHeaders-2                146 ± 0%       146 ± 0%     ~     (all equal)
_requestResponseMapping-2      94.0 ± 0%      94.0 ± 0%     ~     (all equal)
_validation-2                   168 ± 0%       168 ± 0%     ~     (all equal)
_noValidation-2                 168 ± 0%       168 ± 0%     ~     (all equal)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                   638 ± 0%       638 ± 0%     ~     (all equal)
_directGzipHead-2               182 ± 0%       182 ± 0%     ~     (all equal)
_noDirectGzip-2               1.04k ± 0%     1.04k ± 0%     ~     (all equal)
_directGzip_decode-2            638 ± 0%       638 ± 0%     ~     (all equal)
_noDirectGzip_decode-2        1.04k ± 0%     1.04k ± 0%     ~     (all equal)
_htmlResponse-2                 355 ± 0%       355 ± 0%     ~     (all equal)
_jsonBodyManual-2               207 ± 0%       207 ± 0%     ~     (all equal)
_jsonBody-2                     207 ± 0%       207 ± 0%     ~     (all equal)
_jsonBodyValidation-2           193 ± 0%       193 ± 0%     ~     (all equal)
_outputHeaders-2                214 ± 0%       214 ± 0%     ~     (all equal)
_requestResponseMapping-2       108 ± 0%       108 ± 0%     ~     (all equal)
_validation-2                   176 ± 0%       176 ± 0%     ~     (all equal)
_noValidation-2                 176 ± 0%       176 ± 0%     ~     (all equal)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                  322 ± 0%       322 ± 0%     ~     (all equal)
_ok-2                           344 ± 0%       344 ± 0%     ~     (all equal)
_invalidBody-2                  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-2                   103 ± 0%       103 ± 0%     ~     (all equal)
_directGzipHead-2               104 ± 0%       104 ± 0%     ~     (all equal)
_noDirectGzip-2                 117 ± 0%       117 ± 0%     ~     (all equal)
_directGzip_decode-2            116 ± 0%       116 ± 0%     ~     (all equal)
_noDirectGzip_decode-2          130 ± 0%       130 ± 0%     ~     (all equal)
_jsonBody-2                     188 ± 0%       188 ± 0%     ~     (all equal)
_jsonBodyValidation-2           192 ± 0%       192 ± 0%     ~     (all equal)
_outputHeaders-2               77.0 ± 0%      77.0 ± 0%     ~     (all equal)
_requestResponseMapping-2       169 ± 0%       169 ± 0%     ~     (all equal)
_validation-2                   170 ± 0%       170 ± 0%     ~     (all equal)
_noValidation-2                 173 ± 0%       173 ± 0%     ~     (all equal)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                   103 ± 0%       103 ± 0%     ~     (all equal)
_directGzipHead-2               104 ± 0%       104 ± 0%     ~     (all equal)
_noDirectGzip-2                 117 ± 0%       117 ± 0%     ~     (all equal)
_directGzip_decode-2            116 ± 0%       116 ± 0%     ~     (all equal)
_noDirectGzip_decode-2          130 ± 0%       130 ± 0%     ~     (all equal)
_htmlResponse-2                 108 ± 0%       108 ± 0%     ~     (all equal)
_jsonBodyManual-2               195 ± 0%       195 ± 0%     ~     (all equal)
_jsonBody-2                     188 ± 0%       188 ± 0%     ~     (all equal)
_jsonBodyValidation-2           192 ± 0%       192 ± 0%     ~     (all equal)
_outputHeaders-2               88.0 ± 0%      88.0 ± 0%     ~     (all equal)
_requestResponseMapping-2       169 ± 0%       169 ± 0%     ~     (all equal)
_validation-2                   170 ± 0%       170 ± 0%     ~     (all equal)
_noValidation-2                 173 ± 0%       173 ± 0%     ~     (all equal)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                 74.0 ± 0%      74.0 ± 0%     ~     (all equal)
_ok-2                          74.0 ± 0%      74.0 ± 0%     ~     (all equal)
_invalidBody-2                  137 ± 0%       137 ± 0%     ~     (all equal)

name                       old rps        new rps        delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2                 30.3k ± 4%     25.8k ±20%  -14.81%  (p=0.008 n=5+5)
_directGzipHead-2             30.0k ±12%     27.7k ± 3%     ~     (p=0.151 n=5+5)
_noDirectGzip-2               6.16k ± 4%     5.69k ± 1%   -7.53%  (p=0.008 n=5+5)
_directGzip_decode-2          1.75k ± 5%     1.64k ± 2%   -6.44%  (p=0.032 n=5+5)
_noDirectGzip_decode-2        5.97k ± 8%     5.63k ± 4%     ~     (p=0.095 n=5+5)
_jsonBody-2                   13.4k ± 6%     13.0k ± 4%     ~     (p=0.222 n=5+5)
_jsonBodyValidation-2         12.7k ± 8%     11.7k ± 2%   -7.63%  (p=0.016 n=5+5)
_outputHeaders-2              27.5k ±12%     26.3k ± 3%     ~     (p=0.151 n=5+5)
_requestResponseMapping-2     14.5k ± 6%     13.8k ± 2%     ~     (p=0.056 n=5+5)
_validation-2                 13.2k ± 8%     12.5k ± 2%     ~     (p=0.151 n=5+5)
_noValidation-2               18.2k ± 3%     16.7k ± 4%   -8.31%  (p=0.008 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                 27.4k ±18%     25.2k ± 5%     ~     (p=0.151 n=5+5)
_directGzipHead-2             28.6k ± 7%     25.7k ± 5%  -10.20%  (p=0.016 n=5+5)
_noDirectGzip-2               5.69k ± 4%     5.54k ± 4%     ~     (p=0.310 n=5+5)
_directGzip_decode-2          1.59k ± 3%     1.60k ± 2%     ~     (p=0.881 n=5+5)
_noDirectGzip_decode-2        5.85k ± 3%     5.54k ± 3%   -5.27%  (p=0.016 n=5+5)
_htmlResponse-2               15.7k ± 3%     15.2k ± 1%   -3.02%  (p=0.032 n=5+5)
_jsonBodyManual-2             21.3k ± 5%     20.9k ± 1%     ~     (p=0.421 n=5+5)
_jsonBody-2                   14.4k ± 3%     13.5k ± 4%   -6.31%  (p=0.008 n=5+5)
_jsonBodyValidation-2         11.5k ± 3%     10.5k ± 5%   -8.38%  (p=0.008 n=5+5)
_outputHeaders-2              15.4k ± 4%     14.4k ±10%   -6.63%  (p=0.032 n=5+5)
_requestResponseMapping-2     13.3k ± 5%     12.2k ± 3%   -8.42%  (p=0.016 n=5+5)
_validation-2                 12.9k ± 1%     11.2k ± 3%  -13.08%  (p=0.008 n=5+5)
_noValidation-2               17.0k ± 4%     16.3k ± 4%   -4.00%  (p=0.032 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2                22.7k ±12%     22.1k ±11%     ~     (p=0.421 n=5+5)
_ok-2                         22.9k ± 4%     22.4k ± 2%     ~     (p=0.222 n=5+5)
_invalidBody-2                15.1k ± 6%     15.5k ± 3%     ~     (p=0.222 n=5+5)

name                       old alloc/op   new alloc/op   delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2                3.85kB ± 0%    3.86kB ± 0%   +0.17%  (p=0.040 n=5+5)
_directGzipHead-2            3.85kB ± 0%    3.86kB ± 0%   +0.10%  (p=0.024 n=5+5)
_noDirectGzip-2              6.93kB ±20%    7.24kB ±23%     ~     (p=0.690 n=5+5)
_directGzip_decode-2          403kB ± 0%     403kB ± 0%     ~     (p=0.841 n=5+5)
_noDirectGzip_decode-2       6.00kB ± 7%    5.62kB ± 9%     ~     (p=0.151 n=5+5)
_jsonBody-2                  13.1kB ± 0%    13.1kB ± 0%     ~     (p=0.794 n=5+5)
_jsonBodyValidation-2        18.9kB ± 0%    18.9kB ± 0%   +0.05%  (p=0.032 n=5+5)
_outputHeaders-2             3.57kB ± 0%    3.58kB ± 0%     ~     (p=0.167 n=5+5)
_requestResponseMapping-2    16.6kB ± 0%    16.6kB ± 0%     ~     (p=0.738 n=5+5)
_validation-2                16.5kB ± 0%    16.5kB ± 0%     ~     (p=0.341 n=5+5)
_noValidation-2              7.77kB ± 0%    7.77kB ± 0%   +0.08%  (p=0.008 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic goos:linux goarch:amd64
_directGzip-2                3.89kB ± 0%    3.90kB ± 0%   +0.21%  (p=0.008 n=5+5)
_directGzipHead-2            3.88kB ± 0%    3.89kB ± 0%   +0.13%  (p=0.008 n=5+5)
_noDirectGzip-2              7.08kB ±17%    7.17kB ±25%     ~     (p=0.841 n=5+5)
_directGzip_decode-2          403kB ± 0%     403kB ± 0%     ~     (p=0.841 n=5+5)
_noDirectGzip_decode-2       6.36kB ±13%    6.08kB ± 4%     ~     (p=0.310 n=5+5)
_htmlResponse-2              8.04kB ± 0%    8.04kB ± 0%   +0.06%  (p=0.016 n=4+5)
_jsonBodyManual-2            4.50kB ± 0%    4.50kB ± 0%     ~     (p=0.357 n=5+5)
_jsonBody-2                  10.2kB ± 0%    10.2kB ± 0%   +0.07%  (p=0.008 n=5+5)
_jsonBodyValidation-2        19.0kB ± 0%    19.0kB ± 0%   +0.08%  (p=0.016 n=5+5)
_outputHeaders-2             10.4kB ± 0%    10.4kB ± 0%     ~     (p=0.159 n=5+5)
_requestResponseMapping-2    16.7kB ± 0%    16.7kB ± 0%   +0.06%  (p=0.008 n=5+5)
_validation-2                16.6kB ± 0%    16.6kB ± 0%   +0.09%  (p=0.016 n=5+5)
_noValidation-2              7.83kB ± 0%    7.83kB ± 0%   +0.05%  (p=0.016 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2               4.63kB ± 0%    4.63kB ± 0%     ~     (p=0.310 n=5+5)
_ok-2                        4.54kB ± 0%    4.54kB ± 0%     ~     (p=0.686 n=4+4)
_invalidBody-2               8.36kB ± 4%    8.37kB ± 4%     ~     (p=0.897 n=5+5)

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

Patch:
diff --git a/_examples/advanced-generic/file_upload.go b/_examples/advanced-generic/file_upload.go
index caf37d1..be820a2 100644
--- a/_examples/advanced-generic/file_upload.go
+++ b/_examples/advanced-generic/file_upload.go
@@ -31,6 +31,10 @@ func fileUploader() usecase.Interactor {
 	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
diff --git a/_examples/go.mod b/_examples/go.mod
index 633ccbb..75268f7 100644
--- a/_examples/go.mod
+++ b/_examples/go.mod
@@ -7,13 +7,13 @@ replace github.com/swaggest/rest => ../
 require (
 	github.com/bool64/ctxd v1.2.1
 	github.com/bool64/dev v0.2.27
-	github.com/bool64/httpmock v0.1.10
+	github.com/bool64/httpmock v0.1.13
 	github.com/bool64/httptestbench v0.1.4
 	github.com/go-chi/chi/v5 v5.0.8
 	github.com/kelseyhightower/envconfig v1.4.0
 	github.com/rs/cors v1.9.0
 	github.com/stretchr/testify v1.8.2
-	github.com/swaggest/assertjson v1.8.0
+	github.com/swaggest/assertjson v1.8.1
 	github.com/swaggest/jsonschema-go v0.3.51
 	github.com/swaggest/openapi-go v0.2.30
 	github.com/swaggest/swgui v1.6.2
diff --git a/_examples/go.sum b/_examples/go.sum
index 3fb0541..85de626 100644
--- a/_examples/go.sum
+++ b/_examples/go.sum
@@ -6,8 +6,8 @@ github.com/bool64/dev v0.2.5/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zR
 github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
 github.com/bool64/dev v0.2.27 h1:mFT+B74mFVgUeUmm/EbfM6ELPA55lEXBjQ/AOHCwCOc=
 github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
-github.com/bool64/httpmock v0.1.10 h1:cP+JS+nuIe47uwSheiKtoesziyacxbvWfOVo1zczbek=
-github.com/bool64/httpmock v0.1.10/go.mod h1:vodDyrRL4hfWZ6/nvahVzSV4VSK6MSPf0MxyHNQXzuA=
+github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo=
+github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E=
 github.com/bool64/httptestbench v0.1.4 h1:35f9RwWqcnQRXM+sA+GUhWVGSa6XEFlKpNSH9oYzOjI=
 github.com/bool64/httptestbench v0.1.4/go.mod h1:b9ItXGtscs9AcR5oUDnWCTLosQ/DCjiG4euDbHN8T40=
 github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
@@ -55,8 +55,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/swaggest/assertjson v1.8.0 h1:XSg4p6iOZMjtpV2tW2SXfD1GsOOTsWcm+sOADODu/DU=
-github.com/swaggest/assertjson v1.8.0/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
+github.com/swaggest/assertjson v1.8.1 h1:Be2EHY9S2qwKWV+xWZB747Cd7Y79YK6JLdeyrgFvyMo=
+github.com/swaggest/assertjson v1.8.1/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
 github.com/swaggest/form/v5 v5.0.4 h1:hTg+gjUEZG0vgsDdXOPi7I0Xu5OowXKoLZIGYZsoddg=
 github.com/swaggest/form/v5 v5.0.4/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg=
 github.com/swaggest/jsonschema-go v0.3.51 h1:Cl0hFQ/jtBIP8NlHNuwW6ka3J7zzW5r2jxbLSCUByGY=
diff --git a/go.mod b/go.mod
index 0c5e4d8..ae3ca16 100644
--- a/go.mod
+++ b/go.mod
@@ -4,13 +4,13 @@ go 1.17
 
 require (
 	github.com/bool64/dev v0.2.27
-	github.com/bool64/httpmock v0.1.10
+	github.com/bool64/httpmock v0.1.13
 	github.com/bool64/shared v0.1.5
 	github.com/cespare/xxhash/v2 v2.2.0
 	github.com/go-chi/chi/v5 v5.0.8
 	github.com/santhosh-tekuri/jsonschema/v3 v3.1.0
 	github.com/stretchr/testify v1.8.2
-	github.com/swaggest/assertjson v1.8.0
+	github.com/swaggest/assertjson v1.8.1
 	github.com/swaggest/form/v5 v5.0.4
 	github.com/swaggest/jsonschema-go v0.3.51
 	github.com/swaggest/openapi-go v0.2.30
diff --git a/go.sum b/go.sum
index 59664dd..65ca5a6 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ github.com/bool64/dev v0.2.24/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8
 github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
 github.com/bool64/dev v0.2.27 h1:mFT+B74mFVgUeUmm/EbfM6ELPA55lEXBjQ/AOHCwCOc=
 github.com/bool64/dev v0.2.27/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
-github.com/bool64/httpmock v0.1.10 h1:cP+JS+nuIe47uwSheiKtoesziyacxbvWfOVo1zczbek=
-github.com/bool64/httpmock v0.1.10/go.mod h1:vodDyrRL4hfWZ6/nvahVzSV4VSK6MSPf0MxyHNQXzuA=
+github.com/bool64/httpmock v0.1.13 h1:3QpRXQ5kwHLW8xnVT8+Ug7VS6RerhdEFV+RWYC61aVo=
+github.com/bool64/httpmock v0.1.13/go.mod h1:YMTLaypQ3o5DAx78eA/kDRSLec0f+42sLMDmHdmeY+E=
 github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
 github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -68,8 +68,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/swaggest/assertjson v1.8.0 h1:XSg4p6iOZMjtpV2tW2SXfD1GsOOTsWcm+sOADODu/DU=
 github.com/swaggest/assertjson v1.8.0/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
+github.com/swaggest/assertjson v1.8.1 h1:Be2EHY9S2qwKWV+xWZB747Cd7Y79YK6JLdeyrgFvyMo=
+github.com/swaggest/assertjson v1.8.1/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
 github.com/swaggest/form/v5 v5.0.4 h1:hTg+gjUEZG0vgsDdXOPi7I0Xu5OowXKoLZIGYZsoddg=
 github.com/swaggest/form/v5 v5.0.4/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg=
 github.com/swaggest/jsonschema-go v0.3.50/go.mod h1:QfUB5HaZ8y5TiFtCPhM7QwvPNKxTsYxDJaLHTLq6jgU=
diff --git a/request/file.go b/request/file.go
index 0bd2e38..049f4b0 100644
--- a/request/file.go
+++ b/request/file.go
@@ -75,6 +75,8 @@ func setFile(r *http.Request, field reflect.StructField, v reflect.Value) error
 			if field.Tag.Get("required") == "true" {
 				return fmt.Errorf("%w: %q", ErrMissingRequiredFile, name)
 			}
+
+			return nil
 		}
 
 		return fmt.Errorf("failed to get file %q from request: %w", name, err)
diff --git a/response/encoder.go b/response/encoder.go
index ceeda6f..0754809 100644
--- a/response/encoder.go
+++ b/response/encoder.go
@@ -197,11 +197,13 @@ func (h *Encoder) SetupOutput(output interface{}, ht *rest.HandlerTrait) {
 func (h *Encoder) successStatus(output interface{}) int {
 	if outputWithStatus, ok := output.(rest.OutputWithHTTPStatus); ok {
 		return outputWithStatus.HTTPStatus()
-	} else if h.skipRendering && !h.outputWithWriter {
+	}
+
+	if h.skipRendering && !h.outputWithWriter {
 		return http.StatusNoContent
-	} else {
-		return http.StatusOK
 	}
+
+	return http.StatusOK
 }
 
 type jsonEncoder struct {


Test patch:
diff --git a/request/file_test.go b/request/file_test.go
index 10c7cfb..09b776f 100644
--- a/request/file_test.go
+++ b/request/file_test.go
@@ -19,10 +19,12 @@ import (
 	"github.com/swaggest/rest/openapi"
 	"github.com/swaggest/rest/request"
 	"github.com/swaggest/rest/response"
+	"github.com/swaggest/rest/web"
 	"github.com/swaggest/usecase"
 )
 
 type ReqEmb struct {
+	Simple         string                  `formData:"simple"`
 	UploadHeader   *multipart.FileHeader   `formData:"upload"`
 	UploadsHeaders []*multipart.FileHeader `formData:"uploads"`
 }
@@ -33,7 +35,32 @@ type fileReqTest struct {
 	Uploads []multipart.File `formData:"uploads"`
 }
 
-func TestMapper_Decode_fileUploadTag(t *testing.T) {
+func TestDecoder_Decode_fileUploadOptional(t *testing.T) {
+	u := usecase.NewIOI(new(ReqEmb), nil, func(ctx context.Context, input, output interface{}) error {
+		return nil
+	})
+
+	s := web.DefaultService()
+	s.Post("/", u)
+
+	b := bytes.NewBuffer(nil)
+	w := multipart.NewWriter(b)
+	require.NoError(t, w.WriteField("simple", "def"))
+	require.NoError(t, w.Close())
+
+	req, err := http.NewRequest(http.MethodPost, "/", b)
+	require.NoError(t, err)
+
+	req.Header.Set("Content-Type", w.FormDataContentType())
+
+	rw := httptest.NewRecorder()
+	s.ServeHTTP(rw, req)
+
+	assert.Equal(t, http.StatusNoContent, rw.Code)
+	assert.Equal(t, ``, rw.Body.String())
+}
+
+func TestDecoder_Decode_fileUploadTag(t *testing.T) {
 	r := chirouter.NewWrapper(chi.NewRouter())
 	apiSchema := openapi.Collector{}
 	decoderFactory := request.NewDecoderFactory()