Repository: swaggest/rest
Pull request #23 (2021-02-07 21:57:34)

Update dependencies

github-actions[bot]: ### Unit Test Coverage
total:	(statements)	81.0%
<details><summary>Coverage diff with base branch</summary>

```diff
89c89
< github.com/swaggest/rest/request/decoder.go	formDataToURLValues	77.8%
---
> github.com/swaggest/rest/request/decoder.go	formDataToURLValues	66.7%
171c171
< total:	(statements)	81.1%
---
> total:	(statements)	81.0%
```
</details>
<!-- Sticky Pull Request Commentunit-test -->
codecov[bot]: # [Codecov](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=h1) Report
> Merging [#23](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=desc) (d4b454c) into [master](https://codecov.io/gh/swaggest/rest/commit/086dcc93d3e36953240bb667424f5f5e75e8b7a6?el=desc) (086dcc9) will **decrease** coverage by `0.13%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/swaggest/rest/pull/23/graphs/tree.svg?width=650&height=150&src=pr&token=OpLHxxPdmn)](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master      #23      +/-   ##
==========================================
- Coverage   73.31%   73.18%   -0.14%     
==========================================
  Files          26       26              
  Lines        1484     1484              
==========================================
- Hits         1088     1086       -2     
- Misses        250      251       +1     
- Partials      146      147       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `73.18% <ø> (-0.14%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [request/decoder.go](https://codecov.io/gh/swaggest/rest/pull/23/diff?src=pr&el=tree#diff-cmVxdWVzdC9kZWNvZGVyLmdv) | `71.42% <0.00%> (-5.72%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=footer). Last update [086dcc9...d4b454c](https://codecov.io/gh/swaggest/rest/pull/23?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

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

```
Using vendor
name                                    time/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-2  1.67µs ± 2%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                         944ns ± 2%
DecoderFunc_Decode-2                    2.65µs ± 3%
Decoder_Decode_json-2                   30.0µs ± 4%
Decoder_Decode_queryObject-2            6.65µs ± 4%
Decoder_Decode_jsonParam-2              2.33µs ± 2%
DecoderFactory_SetDecoderFunc-2         2.10µs ± 2%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                            14.2µs ± 3%
Middleware_control-2                    4.30µs ± 1%

name                                    alloc/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-2  2.50kB ± 0%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-2                          448B ± 0%
DecoderFunc_Decode-2                    1.51kB ± 0%
Decoder_Decode_json-2                   12.4kB ± 0%
Decoder_Decode_queryObject-2            2.00kB ± 0%
Decoder_Decode_jsonParam-2                752B ± 0%
DecoderFactory_SetDecoderFunc-2         1.02kB ± 0%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-2                            1.11kB ± 1%
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                      169 ± 0%
Decoder_Decode_queryObject-2              36.0 ± 0%
Decoder_Decode_jsonParam-2                12.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>

### Examples Benchmark Result
<details><summary>Benchmark diff with base branch</summary>

```
Using vendor
name                    time/op
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2           34.9µs ± 2%
_directGzipHead-2       35.0µs ± 4%
_noDirectGzip-2          170µs ± 4%
_directGzip_decode-2     597µs ± 2%
_noDirectGzip_decode-2   166µs ± 1%
_jsonBody-2             62.0µs ± 3%
_jsonBodyValidation-2   70.5µs ± 2%
_outputHeaders-2        33.3µs ± 0%
_validation-2           64.3µs ± 3%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2          39.2µs ± 3%
_ok-2                   40.8µs ± 2%
_invalidBody-2          58.6µs ± 2%

name                    B:rcvd/op
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2              639 ± 0%
_directGzipHead-2          183 ± 0%
_noDirectGzip-2          1.04k ± 0%
_directGzip_decode-2       639 ± 0%
_noDirectGzip_decode-2   1.04k ± 0%
_jsonBody-2                203 ± 0%
_jsonBodyValidation-2      194 ± 0%
_outputHeaders-2           155 ± 0%
_validation-2              177 ± 0%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2             337 ± 0%
_ok-2                      359 ± 0%
_invalidBody-2             435 ± 0%

name                    B:sent/op
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2              103 ± 0%
_directGzipHead-2          104 ± 0%
_noDirectGzip-2            117 ± 0%
_directGzip_decode-2       116 ± 0%
_noDirectGzip_decode-2     130 ± 0%
_jsonBody-2                188 ± 0%
_jsonBodyValidation-2      192 ± 0%
_outputHeaders-2          77.0 ± 0%
_validation-2              170 ± 0%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2            74.0 ± 0%
_ok-2                     74.0 ± 0%
_invalidBody-2             137 ± 0%

name                    rps
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2            28.7k ± 2%
_directGzipHead-2        28.6k ± 3%
_noDirectGzip-2          5.88k ± 4%
_directGzip_decode-2     1.67k ± 2%
_noDirectGzip_decode-2   6.02k ± 1%
_jsonBody-2              16.1k ± 3%
_jsonBodyValidation-2    14.2k ± 2%
_outputHeaders-2         30.0k ± 0%
_validation-2            15.5k ± 3%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2           25.5k ± 3%
_ok-2                    24.5k ± 2%
_invalidBody-2           17.1k ± 2%

name                    alloc/op
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2           3.82kB ± 0%
_directGzipHead-2       3.82kB ± 0%
_noDirectGzip-2         6.18kB ±22%
_directGzip_decode-2     403kB ± 0%
_noDirectGzip_decode-2  5.08kB ± 5%
_jsonBody-2             11.7kB ± 0%
_jsonBodyValidation-2   18.2kB ± 0%
_outputHeaders-2        3.60kB ± 0%
_validation-2           16.1kB ± 0%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2          4.77kB ± 0%
_ok-2                   4.68kB ± 0%
_invalidBody-2          8.68kB ± 4%

name                    allocs/op
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-2             39.0 ± 0%
_directGzipHead-2         39.0 ± 0%
_noDirectGzip-2           46.8 ± 4%
_directGzip_decode-2       497 ± 0%
_noDirectGzip_decode-2    47.0 ± 0%
_jsonBody-2                102 ± 0%
_jsonBodyValidation-2      143 ± 0%
_outputHeaders-2          34.0 ± 0%
_validation-2              130 ± 0%
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-2            51.0 ± 0%
_ok-2                     47.0 ± 0%
_invalidBody-2            97.0 ± 0%
```
</details>
<!-- Sticky Pull Request Commentbench -->

Patch:
diff --git a/Makefile b/Makefile
index 02a9cd5..3358680 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,3 @@
-GOLANGCI_LINT_VERSION := "v1.34.1"
 BENCH_COUNT ?= 5
 REF_NAME ?= $(shell git symbolic-ref HEAD --short | tr / - 2>/dev/null)
 
diff --git a/README.md b/README.md
index 80ded9c..e80e19d 100644
--- a/README.md
+++ b/README.md
@@ -308,12 +308,7 @@ func main() {
 	)
 
 	// Create use case interactor.
-	u := struct {
-		usecase.Info
-		usecase.Interactor
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	// Describe use case interactor.
 	u.SetTitle("Greeter")
diff --git a/_examples/advanced/file_multi_upload.go b/_examples/advanced/file_multi_upload.go
index d98a6a7..4f41c08 100644
--- a/_examples/advanced/file_multi_upload.go
+++ b/_examples/advanced/file_multi_upload.go
@@ -9,12 +9,7 @@ import (
 )
 
 func fileMultiUploader() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Files Uploads With 'multipart/form-data'")
 
diff --git a/_examples/advanced/file_upload.go b/_examples/advanced/file_upload.go
index aba48ee..264f683 100644
--- a/_examples/advanced/file_upload.go
+++ b/_examples/advanced/file_upload.go
@@ -9,12 +9,7 @@ import (
 )
 
 func fileUploader() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("File Upload With 'multipart/form-data'")
 
diff --git a/_examples/advanced/gzip_pass_through.go b/_examples/advanced/gzip_pass_through.go
index e14fbcd..e1262f7 100644
--- a/_examples/advanced/gzip_pass_through.go
+++ b/_examples/advanced/gzip_pass_through.go
@@ -49,11 +49,7 @@ func (dc gzipPassThroughContainer) gzipPassThroughStruct() gzipPassThroughStruct
 }
 
 func directGzip() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.WithOutput
-		usecase.WithInput
-	}{}
+	u := usecase.IOInteractor{}
 
 	// Prepare moderately big JSON, resulting JSON payload is ~67KB.
 	rawData := gzipPassThroughStruct{
diff --git a/_examples/advanced/json_body.go b/_examples/advanced/json_body.go
index 0afc817..1628209 100644
--- a/_examples/advanced/json_body.go
+++ b/_examples/advanced/json_body.go
@@ -3,16 +3,12 @@ package main
 import (
 	"context"
 
+	"github.com/swaggest/jsonschema-go"
 	"github.com/swaggest/usecase"
 )
 
 func jsonBody() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	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.")
@@ -23,16 +19,16 @@ func jsonBody() usecase.Interactor {
 	}
 
 	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"`
+		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"`
 		JSONPayload
 	}
 
 	type outputWithJSON struct {
-		Header string `json:"inHeader"`
-		Query  int    `json:"inQuery"`
-		Path   string `json:"inPath"`
+		Header string          `json:"inHeader"`
+		Query  jsonschema.Date `json:"inQuery"`
+		Path   string          `json:"inPath"`
 		JSONPayload
 	}
 
diff --git a/_examples/advanced/json_body_validation.go b/_examples/advanced/json_body_validation.go
index 92fa918..ccffcb7 100644
--- a/_examples/advanced/json_body_validation.go
+++ b/_examples/advanced/json_body_validation.go
@@ -7,12 +7,7 @@ import (
 )
 
 func jsonBodyValidation() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	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.")
diff --git a/_examples/advanced/json_map_body.go b/_examples/advanced/json_map_body.go
index 4d402f3..98d928d 100644
--- a/_examples/advanced/json_map_body.go
+++ b/_examples/advanced/json_map_body.go
@@ -20,12 +20,7 @@ func (j *jsonMapReq) UnmarshalJSON(data []byte) error {
 }
 
 func jsonMapBody() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Request With JSON Map In Body")
 
diff --git a/_examples/advanced/json_param.go b/_examples/advanced/json_param.go
index 34be56b..e72546d 100644
--- a/_examples/advanced/json_param.go
+++ b/_examples/advanced/json_param.go
@@ -7,12 +7,7 @@ import (
 )
 
 func jsonParam() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	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.")
diff --git a/_examples/advanced/json_slice_body.go b/_examples/advanced/json_slice_body.go
index 703efac..948ee65 100644
--- a/_examples/advanced/json_slice_body.go
+++ b/_examples/advanced/json_slice_body.go
@@ -20,12 +20,7 @@ func (j *jsonSliceReq) UnmarshalJSON(data []byte) error {
 }
 
 func jsonSliceBody() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	type jsonOutput struct {
 		Header string           `json:"inHeader"`
diff --git a/_examples/advanced/query_object.go b/_examples/advanced/query_object.go
index 30219d2..c0d0f1c 100644
--- a/_examples/advanced/query_object.go
+++ b/_examples/advanced/query_object.go
@@ -7,12 +7,7 @@ import (
 )
 
 func queryObject() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Request With Object As Query Parameter")
 
diff --git a/_examples/advanced/request_response_mapping.go b/_examples/advanced/request_response_mapping.go
index 41d57b4..33504b4 100644
--- a/_examples/advanced/request_response_mapping.go
+++ b/_examples/advanced/request_response_mapping.go
@@ -7,12 +7,7 @@ import (
 )
 
 func reqRespMapping() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Request Response Mapping")
 	u.SetName("reqRespMapping")
diff --git a/_examples/advanced/validation.go b/_examples/advanced/validation.go
index 0afacc4..8be3737 100644
--- a/_examples/advanced/validation.go
+++ b/_examples/advanced/validation.go
@@ -7,12 +7,7 @@ import (
 )
 
 func validation() usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Validation")
 	u.SetDescription("Input/Output with validation.")
diff --git a/_examples/basic/main.go b/_examples/basic/main.go
index 1bb3846..9b2b99a 100644
--- a/_examples/basic/main.go
+++ b/_examples/basic/main.go
@@ -50,12 +50,7 @@ func main() {
 	)
 
 	// Create use case interactor.
-	u := struct {
-		usecase.Info
-		usecase.Interactor
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	// Describe use case interactor.
 	u.SetTitle("Greeter")
diff --git a/_examples/go.mod b/_examples/go.mod
index 43b3af5..b96438b 100644
--- a/_examples/go.mod
+++ b/_examples/go.mod
@@ -11,9 +11,9 @@ require (
 	github.com/kelseyhightower/envconfig v1.4.0
 	github.com/stretchr/testify v1.7.0
 	github.com/swaggest/assertjson v1.6.2
-	github.com/swaggest/jsonschema-go v0.3.13
+	github.com/swaggest/jsonschema-go v0.3.14
 	github.com/swaggest/openapi-go v0.2.9
-	github.com/swaggest/rest v0.1.11
+	github.com/swaggest/rest v0.1.17
 	github.com/swaggest/swgui v1.1.2
 	github.com/swaggest/usecase v0.1.1
 	github.com/valyala/fasthttp v1.17.0
diff --git a/_examples/go.sum b/_examples/go.sum
index 0528fb1..041ff5a 100644
--- a/_examples/go.sum
+++ b/_examples/go.sum
@@ -117,13 +117,14 @@ github.com/swaggest/assertjson v1.4.1/go.mod h1:v7atNMMlIa5ry2H1rgCHhvz7eho8yfP8
 github.com/swaggest/assertjson v1.6.0/go.mod h1:2dZU3TJoGcH+QPrekon0+zG5hJnZUpdEAxiLoxmJALI=
 github.com/swaggest/assertjson v1.6.2 h1:4v4ueAy466hisGIeQ2WmFDyOJiE0YrCDDRaSXor642I=
 github.com/swaggest/assertjson v1.6.2/go.mod h1:7/CWJAKS2t0KXIGsh5no8qyRXluwQ4fVduV3+Jue/MY=
-github.com/swaggest/form v3.6.4+incompatible h1:K0EaZjf8C7cScuZgnJG+Sg0GUGAtjPZivTv1jN+1ni4=
-github.com/swaggest/form v3.6.4+incompatible/go.mod h1:eTJPpSayjnJlOQQbDYsSHlbREbSAtudNW/Y6HouVWr0=
+github.com/swaggest/form v1.11.1 h1:dNRMhld2VkVA6J9sjKaWSoabEP92G5NNlLs9wW+zN/Q=
+github.com/swaggest/form v1.11.1/go.mod h1:XI/xmw62iJuKxhbqvxOj1ri7VJFAaeRsX5qNdHVkbB4=
 github.com/swaggest/jsonschema-go v0.2.1/go.mod h1:QFauBdPTrU1UltwocM5FzOWnVjVVtcWkJWG3NlK9sV0=
 github.com/swaggest/jsonschema-go v0.2.4/go.mod h1:m4VV88Gbi7lCrt9ckJzigK1rMlEeFjdZUkJr1o5MnDE=
 github.com/swaggest/jsonschema-go v0.3.7/go.mod h1:TrWgbug4p2ZgcxnHDz+CvYvEtJ5KckL/XOV4mSR6FGw=
-github.com/swaggest/jsonschema-go v0.3.13 h1:QKgsj3PrrNZBs68JZ6TJZTFT943AO48oGIsVwWhO47s=
 github.com/swaggest/jsonschema-go v0.3.13/go.mod h1:INO3Dt0DeyNCbQbqMXNpMQ489BcyRtSb/k62OfmHbpY=
+github.com/swaggest/jsonschema-go v0.3.14 h1:HmXY9SbMtwedXM6JOlRcAOxtJ0wH2WURWlnow40CAoo=
+github.com/swaggest/jsonschema-go v0.3.14/go.mod h1:ohKskUhEMf/bhSi2zY0A5aLZoMz7ZkEafEvniNKBaQg=
 github.com/swaggest/openapi-go v0.1.3/go.mod h1:Zx4ZgJ7XvlFH9wCOHE7u8RAjLfiHAnCHeaD5kUDujVM=
 github.com/swaggest/openapi-go v0.1.13/go.mod h1:fju3Ka5zb8qBKf4789zLNVUqITydWLDjtPloZhhYHL8=
 github.com/swaggest/openapi-go v0.2.9 h1:JJQrDSRtKMycIkLju97yjhJbw72mqhsCDJjqFB8HvSs=
@@ -242,8 +243,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
-gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/_examples/task-api/internal/usecase/create_task.go b/_examples/task-api/internal/usecase/create_task.go
index 72a6708..349cdaa 100644
--- a/_examples/task-api/internal/usecase/create_task.go
+++ b/_examples/task-api/internal/usecase/create_task.go
@@ -13,12 +13,7 @@ import (
 func CreateTask(deps interface {
 	TaskCreator() task.Creator
 }) usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetName("createTask")
 	u.SetTitle("Create Task")
diff --git a/_examples/task-api/internal/usecase/find_task.go b/_examples/task-api/internal/usecase/find_task.go
index 1861f35..d9dedfb 100644
--- a/_examples/task-api/internal/usecase/find_task.go
+++ b/_examples/task-api/internal/usecase/find_task.go
@@ -12,12 +12,7 @@ import (
 func FindTask(deps interface {
 	TaskFinder() task.Finder
 }) usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetName("findTask")
 	u.SetTitle("Find Task")
diff --git a/_examples/task-api/internal/usecase/find_tasks.go b/_examples/task-api/internal/usecase/find_tasks.go
index 0402a7b..7e1c96f 100644
--- a/_examples/task-api/internal/usecase/find_tasks.go
+++ b/_examples/task-api/internal/usecase/find_tasks.go
@@ -13,12 +13,7 @@ import (
 func FindTasks(deps interface {
 	TaskFinder() task.Finder
 }) usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetName("findTasks")
 	u.SetTitle("Find Tasks")
diff --git a/_examples/task-api/internal/usecase/finish_task.go b/_examples/task-api/internal/usecase/finish_task.go
index 90c0e53..47f6910 100644
--- a/_examples/task-api/internal/usecase/finish_task.go
+++ b/_examples/task-api/internal/usecase/finish_task.go
@@ -14,12 +14,7 @@ type finishTaskDeps interface {
 
 // FinishTask creates usecase interactor.
 func FinishTask(deps finishTaskDeps) usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetName("closeTask")
 	u.SetTitle("Finish Task")
diff --git a/_examples/task-api/internal/usecase/update_task.go b/_examples/task-api/internal/usecase/update_task.go
index e29fb87..3f5acd6 100644
--- a/_examples/task-api/internal/usecase/update_task.go
+++ b/_examples/task-api/internal/usecase/update_task.go
@@ -17,12 +17,7 @@ type updateTask struct {
 func UpdateTask(deps interface {
 	TaskUpdater() task.Updater
 }) usecase.Interactor {
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetName("updateTask")
 	u.SetTitle("Update Task")
diff --git a/go.mod b/go.mod
index e5eb8da..5cec6db 100644
--- a/go.mod
+++ b/go.mod
@@ -7,13 +7,12 @@ require (
 	github.com/bool64/shared v0.1.1
 	github.com/cespare/xxhash/v2 v2.1.1
 	github.com/go-chi/chi v1.5.1
-	github.com/iancoleman/orderedmap v0.2.0 // indirect
 	github.com/santhosh-tekuri/jsonschema/v2 v2.2.0
 	github.com/stretchr/testify v1.7.0
 	github.com/swaggest/assertjson v1.6.2
-	github.com/swaggest/form v3.6.4+incompatible
+	github.com/swaggest/form v1.11.1
+	github.com/swaggest/jsonschema-go v0.3.14
 	github.com/swaggest/openapi-go v0.2.9
 	github.com/swaggest/refl v0.1.6
 	github.com/swaggest/usecase v0.1.1
-	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
 )
diff --git a/go.sum b/go.sum
index d914380..9e9adbe 100644
--- a/go.sum
+++ b/go.sum
@@ -103,13 +103,14 @@ github.com/swaggest/assertjson v1.4.1/go.mod h1:v7atNMMlIa5ry2H1rgCHhvz7eho8yfP8
 github.com/swaggest/assertjson v1.6.0/go.mod h1:2dZU3TJoGcH+QPrekon0+zG5hJnZUpdEAxiLoxmJALI=
 github.com/swaggest/assertjson v1.6.2 h1:4v4ueAy466hisGIeQ2WmFDyOJiE0YrCDDRaSXor642I=
 github.com/swaggest/assertjson v1.6.2/go.mod h1:7/CWJAKS2t0KXIGsh5no8qyRXluwQ4fVduV3+Jue/MY=
-github.com/swaggest/form v3.6.4+incompatible h1:K0EaZjf8C7cScuZgnJG+Sg0GUGAtjPZivTv1jN+1ni4=
-github.com/swaggest/form v3.6.4+incompatible/go.mod h1:eTJPpSayjnJlOQQbDYsSHlbREbSAtudNW/Y6HouVWr0=
+github.com/swaggest/form v1.11.1 h1:dNRMhld2VkVA6J9sjKaWSoabEP92G5NNlLs9wW+zN/Q=
+github.com/swaggest/form v1.11.1/go.mod h1:XI/xmw62iJuKxhbqvxOj1ri7VJFAaeRsX5qNdHVkbB4=
 github.com/swaggest/jsonschema-go v0.2.1/go.mod h1:QFauBdPTrU1UltwocM5FzOWnVjVVtcWkJWG3NlK9sV0=
 github.com/swaggest/jsonschema-go v0.2.4/go.mod h1:m4VV88Gbi7lCrt9ckJzigK1rMlEeFjdZUkJr1o5MnDE=
 github.com/swaggest/jsonschema-go v0.3.7/go.mod h1:TrWgbug4p2ZgcxnHDz+CvYvEtJ5KckL/XOV4mSR6FGw=
-github.com/swaggest/jsonschema-go v0.3.13 h1:QKgsj3PrrNZBs68JZ6TJZTFT943AO48oGIsVwWhO47s=
 github.com/swaggest/jsonschema-go v0.3.13/go.mod h1:INO3Dt0DeyNCbQbqMXNpMQ489BcyRtSb/k62OfmHbpY=
+github.com/swaggest/jsonschema-go v0.3.14 h1:HmXY9SbMtwedXM6JOlRcAOxtJ0wH2WURWlnow40CAoo=
+github.com/swaggest/jsonschema-go v0.3.14/go.mod h1:ohKskUhEMf/bhSi2zY0A5aLZoMz7ZkEafEvniNKBaQg=
 github.com/swaggest/openapi-go v0.1.3/go.mod h1:Zx4ZgJ7XvlFH9wCOHE7u8RAjLfiHAnCHeaD5kUDujVM=
 github.com/swaggest/openapi-go v0.1.13/go.mod h1:fju3Ka5zb8qBKf4789zLNVUqITydWLDjtPloZhhYHL8=
 github.com/swaggest/openapi-go v0.2.9 h1:JJQrDSRtKMycIkLju97yjhJbw72mqhsCDJjqFB8HvSs=
@@ -215,8 +216,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
-gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=


Test patch:
diff --git a/_examples/advanced/_testdata/openapi.json b/_examples/advanced/_testdata/openapi.json
index b39e6c7..1be84c4 100644
--- a/_examples/advanced/_testdata/openapi.json
+++ b/_examples/advanced/_testdata/openapi.json
@@ -37,6 +37,7 @@
     },
     "/gzip-pass-through":{
       "get":{
+        "summary":"","description":"","operationId":"",
         "parameters":[
           {
             "name":"plainStruct","in":"query","description":"Output plain structure instead of gzip container.",
@@ -55,6 +56,7 @@
         }
       },
       "head":{
+        "summary":"","description":"","operationId":"",
         "parameters":[
           {
             "name":"plainStruct","in":"query","description":"Output plain structure instead of gzip container.",
@@ -109,7 +111,7 @@
         "parameters":[
           {
             "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","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,
@@ -406,8 +408,8 @@
       "AdvancedOutputWithJSONType2":{
         "type":"object",
         "properties":{
-          "id":{"type":"integer"},"inHeader":{"type":"string"},"inPath":{"type":"string"},"inQuery":{"type":"integer"},
-          "name":{"type":"string"}
+          "id":{"type":"integer"},"inHeader":{"type":"string"},"inPath":{"type":"string"},
+          "inQuery":{"type":"string","format":"date"},"name":{"type":"string"}
         }
       },
       "AdvancedOutputWithJSONType3":{
diff --git a/_examples/advanced/json_body_test.go b/_examples/advanced/json_body_test.go
index 4208167..b3972c2 100644
--- a/_examples/advanced/json_body_test.go
+++ b/_examples/advanced/json_body_test.go
@@ -19,7 +19,7 @@ func Benchmark_jsonBody(b *testing.B) {
 
 	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
 		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/json-body/abc?in_query=123")
+		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"}`))
diff --git a/openapi/collector_test.go b/openapi/collector_test.go
index 869d30b..df84406 100644
--- a/openapi/collector_test.go
+++ b/openapi/collector_test.go
@@ -6,10 +6,12 @@ import (
 	"net/http"
 	"net/http/httptest"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/swaggest/assertjson"
+	jschema "github.com/swaggest/jsonschema-go"
 	"github.com/swaggest/openapi-go/openapi3"
 	"github.com/swaggest/rest"
 	"github.com/swaggest/rest/jsonschema"
@@ -112,19 +114,14 @@ func TestCollector_Collect(t *testing.T) {
 func TestCollector_Collect_requestMapping(t *testing.T) {
 	type input struct {
 		InHeader   string `minLength:"2"`
-		InQuery    int
-		InCookie   float64
-		InFormData string
+		InQuery    jschema.Date
+		InCookie   *time.Time
+		InFormData time.Time
 		InPath     bool
 		InFile     multipart.File
 	}
 
-	u := struct {
-		usecase.Interactor
-		usecase.Info
-		usecase.WithInput
-		usecase.WithOutput
-	}{}
+	u := usecase.IOInteractor{}
 
 	u.SetTitle("Title")
 	u.SetName("name")
@@ -147,43 +144,40 @@ func TestCollector_Collect_requestMapping(t *testing.T) {
 
 	require.NoError(t, collector.Collect(http.MethodPost, "/test/{in-path}", u, h))
 
-	j, err := assertjson.MarshalIndentCompact(collector.Reflector().SpecEns(), "", "  ", 100)
-	require.NoError(t, err)
-
-	assertjson.Equal(t, []byte(`{
-	  "openapi":"3.0.3","info":{"title":"","version":""},
-	  "paths":{
-		"/test/{in-path}":{
-		  "post":{
-			"summary":"Title","description":"","operationId":"name",
-			"parameters":[
-			  {"name":"in_query","in":"query","schema":{"type":"integer"}},
-			  {"name":"in-path","in":"path","required":true,"schema":{"type":"boolean"}},
-			  {"name":"in_cookie","in":"cookie","schema":{"type":"number"}},
-			  {"name":"X-In-Header","in":"header","schema":{"minLength":2,"type":"string"}}
-			],
-			"requestBody":{
-			  "content":{
-				"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FormDataOpenapiTestInput"}}
-			  }
-			},
-			"responses":{"204":{"description":"No Content"}},"deprecated":true
-		  }
-		}
-	  },
-	  "components":{
-		"schemas":{
-		  "FormDataMultipartFile":{"type":"string","format":"binary","nullable":true},
-		  "FormDataOpenapiTestInput":{
-			"type":"object",
-			"properties":{
-			  "in_form_data":{"type":"string"},
-			  "upload":{"$ref":"#/components/schemas/FormDataMultipartFile"}
-			}
+	assertjson.EqualMarshal(t, []byte(`{
+  "openapi":"3.0.3","info":{"title":"","version":""},
+  "paths":{
+	"/test/{in-path}":{
+	  "post":{
+		"summary":"Title","description":"","operationId":"name",
+		"parameters":[
+		  {"name":"in_query","in":"query","schema":{"type":"string","format":"date"}},
+		  {"name":"in-path","in":"path","required":true,"schema":{"type":"boolean"}},
+		  {"name":"in_cookie","in":"cookie","schema":{"type":"string","format":"date-time"}},
+		  {"name":"X-In-Header","in":"header","schema":{"minLength":2,"type":"string"}}
+		],
+		"requestBody":{
+		  "content":{
+			"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FormDataOpenapiTestInput"}}
 		  }
+		},
+		"responses":{"204":{"description":"No Content"}},"deprecated":true
+	  }
+	}
+  },
+  "components":{
+	"schemas":{
+	  "FormDataMultipartFile":{"type":"string","format":"binary","nullable":true},
+	  "FormDataOpenapiTestInput":{
+		"type":"object",
+		"properties":{
+		  "in_form_data":{"type":"string","format":"date-time"},
+		  "upload":{"$ref":"#/components/schemas/FormDataMultipartFile"}
 		}
 	  }
-	}`), j, string(j))
+	}
+  }
+}`), collector.Reflector().SpecEns())
 
 	val := validatorMock{
 		AddSchemaFunc: func(in rest.ParamIn, name string, schemaData []byte, required bool) error {
diff --git a/request/decoder_test.go b/request/decoder_test.go
index 5a5dcb3..f8accf4 100644
--- a/request/decoder_test.go
+++ b/request/decoder_test.go
@@ -2,13 +2,16 @@ package request_test
 
 import (
 	"context"
+	"fmt"
 	"net/http"
 	"net/url"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	jschema "github.com/swaggest/jsonschema-go"
 	"github.com/swaggest/rest"
 	"github.com/swaggest/rest/jsonschema"
 	"github.com/swaggest/rest/openapi"
@@ -247,7 +250,7 @@ func TestDecoder_Decode_queryObject(t *testing.T) {
 	err = dec.Decode(req, input, nil)
 	assert.Error(t, err)
 	assert.Equal(t, rest.RequestErrors{"query:in_query": []string{
-		"#: Invalid Integer Value 'c' Type 'int' Namespace 'in_query'",
+		"#: invalid integer value 'c' type 'int' namespace 'in_query'",
 	}}, err)
 }
 
@@ -351,6 +354,25 @@ func TestDecoder_Decode_error(t *testing.T) {
 	err = d.Decode(r, in, nil)
 	assert.EqualError(t, err, "bad request")
 	assert.Equal(t, rest.RequestErrors{"query:q": []string{
-		"#: Invalid Integer Value 'undefined' Type 'int' Namespace 'q'",
+		"#: invalid integer value 'undefined' type 'int' namespace 'q'",
 	}}, err)
 }
+
+func TestDecoder_Decode_dateTime(t *testing.T) {
+	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet,
+		"/?time=2020-04-04T00:00:00Z&date=2020-04-04", nil)
+	assert.NoError(t, err)
+
+	type reqTest struct {
+		Time time.Time    `query:"time"`
+		Date jschema.Date `query:"date"`
+	}
+
+	input := new(reqTest)
+	dec := request.NewDecoderFactory().MakeDecoder(http.MethodGet, input, nil)
+	validator := jsonschema.NewFactory(&openapi.Collector{}, &openapi.Collector{}).
+		MakeRequestValidator(http.MethodGet, input, nil)
+
+	err = dec.Decode(req, input, validator)
+	assert.NoError(t, err, fmt.Sprintf("%v", err))
+}