openapi_first 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f1e3ae677c078e5e4b64641c76c40a66994edb8599d9001e3673458eb83338d
4
- data.tar.gz: 6e394c9017964515be4e8970899fe697480600753ca6e81db78d34faed7c982b
3
+ metadata.gz: 1c24075e5a05299387bba14bb16f931cf5e0f6cad58f0b0af04603ceb568dd78
4
+ data.tar.gz: 6e3eba2165048d139af385e736320157d6332f307d1cf99afe25172d5d48910d
5
5
  SHA512:
6
- metadata.gz: e41290229c5e5bc7d65179783b6b1ec0403ab987433c5b65535c10d3fee00a42440626f26f2a8ffd02d69a63b64684780165cc4398baf873842e20731570a076
7
- data.tar.gz: b93594502a2dff93be5b0bff277f49431c40cae4a77a263acfac14370c855dbd424ac36156b832ec2f2ef1f892e44c0c7aaf84d6b567d772220da0ec991357a5
6
+ metadata.gz: 65b51042f045570f3f357108aee08519be8e0f0b0ca2b997fa4ba3bbb49bd4febb98a28efb624f6cacd41074383c7b8920748c2997fe5d943108d3d72db5194e
7
+ data.tar.gz: 9188f1624b57d2eb5eea004bef5b086037681603a7dc788b1810faa42b44005360663326d81aa53ba549442c8667fef6b4830dfc542f7f39e77c011db25f01f2
data/CHANGELOG.md CHANGED
@@ -1,38 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.0
4
+
5
+ - Populate default parameter values
6
+
7
+ ## 0.14.3
8
+
9
+ - Use json_refs to resolve OpenAPI file. This removes oas_parser and ActiveSupport from list of dependencies
10
+
11
+ ## 0.14.2
12
+
13
+ - Empty query parameters are parsed and request validation returns 400 if an empty string is not allowed. Note that this does not look at `allowEmptyValue` in any way, because allowEmptyValue is deprecated.
14
+
15
+ ## 0.14.1
16
+
17
+ - Bugfix: Don't mix path- and operation-level parameters for request validation
18
+
3
19
  ## 0.14.0
20
+
4
21
  - Handle custom x-handler field in the API description to find a handler method not based on operationId
5
22
  - Add `resolver` option to provide a custom resolver to find a handler method
6
23
 
7
24
  ## 0.13.3
25
+
8
26
  - Better error message if string does not match format
9
27
  - readOnly and writeOnly just works when used inside allOf
10
28
 
11
29
  ## 0.13.2
30
+
12
31
  - Return indicator (`source: { parameter: 'list/1' }`) in error response body when array item in query parameter is invalid
13
32
 
14
33
  ## 0.13.0
34
+
15
35
  - Add support for arrays in query parameters (style: form, explode: false)
16
36
  - Remove warning when handler is not implemented
17
37
 
18
38
  ## 0.12.5
39
+
19
40
  - Add `not_found: :continue` option to Router to make it do nothing if request is unknown
20
41
 
21
42
  ## 0.12.4
43
+
22
44
  - content-type is found while ignoring additional content-type parameters (`application/json` is found when request/response content-type is `application/json; charset=UTF8`)
23
45
  - Support wildcard mime-types when finding the content-type
24
46
 
25
47
  ## 0.12.3
48
+
26
49
  - Add `response_validation:`, `router_raise_error` options to standalone mode.
27
50
 
28
51
  ## 0.12.2
52
+
29
53
  - Allow response to have no media type object specified
30
54
 
31
55
  ## 0.12.1
56
+
32
57
  - Fix response when handler returns 404 or 405
33
58
  - Don't validate the response content if status is 204 (no content)
34
59
 
35
60
  ## 0.12.0
61
+
36
62
  - Change `ResponseValidator` to raise an exception if it found a problem
37
63
  - Params have symbolized keys now
38
64
  - Remove `not_found` option from Router. Return 405 if HTTP verb is not allowed (via Hanami::Router)
@@ -44,6 +70,7 @@
44
70
  - Add `Operation#name` that returns a human readable name for an operation
45
71
 
46
72
  ## 0.11.0
73
+
47
74
  - Raise error if you forgot to add the Router middleware
48
75
  - Make OpenapiFirst.app raise an error in test env when request path is not specified
49
76
  - Rename OperationResolver to Responder
@@ -52,48 +79,60 @@
52
79
  - Move namespace option from Router to OperationResolver
53
80
 
54
81
  ## 0.10.2
82
+
55
83
  - Return 400 if request body has invalid JSON ([issue](https://github.com/ahx/openapi_first/issues/73)) thanks Thomas Frütel
56
84
 
57
85
  ## 0.10.1
86
+
58
87
  - Fix duplicated key in `required` when generating JSON schema for `some[thing]` parameters
59
88
 
60
89
  ## 0.10.0
90
+
61
91
  - Add support for query parameters named `"some[thing]"` ([issue](https://github.com/ahx/openapi_first/issues/40))
62
92
 
63
93
  ## 0.9.0
94
+
64
95
  - Make request validation usable standalone
65
96
 
66
97
  ## 0.8.0
98
+
67
99
  - Add merged parameter and request body available to env at `env[OpenapiFirst::INBOX]` in request validation
68
100
  - Path and query parameters with `type: boolean` now get converted to `true`/`false`
69
101
  - Rename `OpenapiFirst::PARAMS` to `OpenapiFirst::PARAMETERS`
70
102
 
71
103
  ## 0.7.1
104
+
72
105
  - Add missing `require` to work with new version of `oas_parser`
73
106
 
74
107
  ## 0.7.0
108
+
75
109
  - Make use of hanami-router, because it's fast
76
110
  - Remove option `allow_unknown_query_paramerters`
77
111
  - Move the namespace option to Router
78
- - Convert numeric path and query parameters to `Integer` or `Float`
112
+ - Convert numeric path and query parameters to `Integer` or `Float`
79
113
  - Pass the Rack env if your action class' initializers accepts an argument
80
114
  - Respec rack's `env['SCRIPT_NAME']` in router
81
115
  - Add MIT license
82
116
 
83
117
  ## 0.6.10
118
+
84
119
  - Bugfix: params.env['unknown'] now returns `nil` as expected. Thanks @tristandruyen.
85
120
 
86
121
  ## 0.6.9
122
+
87
123
  - Removed radix tree, because of a bug (https://github.com/namusyaka/r2ree-ruby/issues/2)
88
124
 
89
125
  ## 0.6.8
126
+
90
127
  - Performance: About 25% performance increase (i/s) with help of c++ based radix-tree and some optimizations
91
128
  - Update dependencies
92
129
 
93
130
  ## 0.6.7
131
+
94
132
  - Fix: version number of oas_parser
95
133
 
96
134
  ## 0.6.6
135
+
97
136
  - Remove warnings for Ruby 2.7
98
137
 
99
138
  ## 0.6.5
data/Gemfile.lock CHANGED
@@ -1,121 +1,93 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openapi_first (0.14.0)
4
+ openapi_first (0.15.0)
5
5
  deep_merge (>= 1.2.1)
6
- hanami-router (~> 2.0.alpha3)
7
- hanami-utils (~> 2.0.alpha1)
6
+ hanami-router (~> 2.0.alpha5)
7
+ hanami-utils (~> 2.0.alpha3)
8
+ json_refs (>= 0.1.7)
8
9
  json_schemer (~> 0.2.16)
9
10
  multi_json (~> 1.14)
10
- oas_parser (~> 0.25.1)
11
11
  rack (~> 2.2)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activesupport (6.1.4)
17
- concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 1.6, < 2)
19
- minitest (>= 5.1)
20
- tzinfo (~> 2.0)
21
- zeitwerk (~> 2.3)
22
- addressable (2.8.0)
23
- public_suffix (>= 2.0.2, < 5.0)
24
16
  ast (2.4.2)
25
- builder (3.2.4)
26
17
  coderay (1.1.3)
27
18
  concurrent-ruby (1.1.9)
28
- deep_merge (1.2.1)
29
- diff-lcs (1.4.4)
19
+ deep_merge (1.2.2)
20
+ diff-lcs (1.5.0)
30
21
  dry-transformer (0.1.1)
31
- ecma-re-validator (0.3.0)
32
- regexp_parser (~> 2.0)
22
+ ecma-re-validator (0.4.0)
23
+ regexp_parser (~> 2.2)
33
24
  hana (1.3.7)
34
25
  hanami-router (2.0.0.alpha5)
35
26
  mustermann (~> 1.0)
36
27
  mustermann-contrib (~> 1.0)
37
28
  rack (~> 2.0)
38
- hanami-utils (2.0.0.alpha2)
29
+ hanami-utils (2.0.0.alpha3)
39
30
  concurrent-ruby (~> 1.0)
40
31
  dry-transformer (~> 0.1)
41
32
  hansi (0.2.0)
42
- hash-deep-merge (0.1.1)
43
- i18n (1.8.10)
44
- concurrent-ruby (~> 1.0)
33
+ json_refs (0.1.7)
34
+ hana
45
35
  json_schemer (0.2.18)
46
36
  ecma-re-validator (~> 0.3)
47
37
  hana (~> 1.3)
48
38
  regexp_parser (~> 2.0)
49
39
  uri_template (~> 0.7)
50
40
  method_source (1.0.0)
51
- mini_portile2 (2.6.1)
52
- minitest (5.14.4)
53
41
  multi_json (1.15.0)
54
42
  mustermann (1.1.1)
55
43
  ruby2_keywords (~> 0.0.1)
56
44
  mustermann-contrib (1.1.1)
57
45
  hansi (~> 0.2.0)
58
46
  mustermann (= 1.1.1)
59
- nokogiri (1.12.2)
60
- mini_portile2 (~> 2.6.1)
61
- racc (~> 1.4)
62
- oas_parser (0.25.4)
63
- activesupport (>= 4.0.0)
64
- addressable (~> 2.3)
65
- builder (~> 3.2.3)
66
- deep_merge (~> 1.2.1)
67
- hash-deep-merge
68
- mustermann-contrib (~> 1.1.1)
69
- nokogiri
70
- parallel (1.20.1)
71
- parser (3.0.2.0)
47
+ parallel (1.21.0)
48
+ parser (3.1.0.0)
72
49
  ast (~> 2.4.1)
73
50
  pry (0.14.1)
74
51
  coderay (~> 1.1)
75
52
  method_source (~> 1.0)
76
- public_suffix (4.0.6)
77
- racc (1.5.2)
78
53
  rack (2.2.3)
79
54
  rack-test (1.1.0)
80
55
  rack (>= 1.0, < 3)
81
- rainbow (3.0.0)
56
+ rainbow (3.1.1)
82
57
  rake (13.0.6)
83
- regexp_parser (2.1.1)
58
+ regexp_parser (2.2.1)
84
59
  rexml (3.2.5)
85
- rspec (3.10.0)
86
- rspec-core (~> 3.10.0)
87
- rspec-expectations (~> 3.10.0)
88
- rspec-mocks (~> 3.10.0)
89
- rspec-core (3.10.1)
90
- rspec-support (~> 3.10.0)
91
- rspec-expectations (3.10.1)
60
+ rspec (3.11.0)
61
+ rspec-core (~> 3.11.0)
62
+ rspec-expectations (~> 3.11.0)
63
+ rspec-mocks (~> 3.11.0)
64
+ rspec-core (3.11.0)
65
+ rspec-support (~> 3.11.0)
66
+ rspec-expectations (3.11.0)
92
67
  diff-lcs (>= 1.2.0, < 2.0)
93
- rspec-support (~> 3.10.0)
94
- rspec-mocks (3.10.2)
68
+ rspec-support (~> 3.11.0)
69
+ rspec-mocks (3.11.0)
95
70
  diff-lcs (>= 1.2.0, < 2.0)
96
- rspec-support (~> 3.10.0)
97
- rspec-support (3.10.2)
98
- rubocop (1.18.4)
71
+ rspec-support (~> 3.11.0)
72
+ rspec-support (3.11.0)
73
+ rubocop (1.25.1)
99
74
  parallel (~> 1.10)
100
- parser (>= 3.0.0.0)
75
+ parser (>= 3.1.0.0)
101
76
  rainbow (>= 2.2.2, < 4.0)
102
77
  regexp_parser (>= 1.8, < 3.0)
103
78
  rexml
104
- rubocop-ast (>= 1.8.0, < 2.0)
79
+ rubocop-ast (>= 1.15.1, < 2.0)
105
80
  ruby-progressbar (~> 1.7)
106
81
  unicode-display_width (>= 1.4.0, < 3.0)
107
- rubocop-ast (1.9.0)
82
+ rubocop-ast (1.15.2)
108
83
  parser (>= 3.0.1.1)
109
84
  ruby-progressbar (1.11.0)
110
85
  ruby2_keywords (0.0.5)
111
- tzinfo (2.0.4)
112
- concurrent-ruby (~> 1.0)
113
- unicode-display_width (2.0.0)
86
+ unicode-display_width (2.1.0)
114
87
  uri_template (0.7.0)
115
- zeitwerk (2.4.2)
116
88
 
117
89
  PLATFORMS
118
- ruby
90
+ x86_64-darwin-20
119
91
 
120
92
  DEPENDENCIES
121
93
  bundler (~> 2)
@@ -127,4 +99,4 @@ DEPENDENCIES
127
99
  rubocop
128
100
 
129
101
  BUNDLED WITH
130
- 2.2.3
102
+ 2.3.7
data/README.md CHANGED
@@ -15,6 +15,7 @@ This gem is inspired by [committee](https://github.com/interagent/committee) (Ru
15
15
  Here's a [comparison between committee and openapi_first](https://gist.github.com/ahx/1538c31f0652f459861713b5259e366a).
16
16
 
17
17
  ## Rack middlewares
18
+
18
19
  OpenapiFirst consists of these Rack middlewares:
19
20
 
20
21
  - [`OpenapiFirst::Router`](#OpenapiFirst::Router) – Finds the OpenAPI operation for the current request or returns 404 if no operation was found. This can be customized.
@@ -23,6 +24,7 @@ OpenapiFirst consists of these Rack middlewares:
23
24
  - [`OpenapiFirst::ResponseValidation`](#OpenapiFirst::ResponseValidation) Validates the response and raises an exception if the response body is invalid.
24
25
 
25
26
  ## OpenapiFirst::Router
27
+
26
28
  You always have to add this middleware first in order to make the other middlewares work.
27
29
 
28
30
  ```ruby
@@ -33,11 +35,11 @@ This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation obj
33
35
 
34
36
  ### Options and defaults
35
37
 
36
- | Name | Possible values | Description | Default
37
- |:---|---|---|---|
38
- |`spec:`| | The spec loaded via `OpenapiFirst.load` ||
39
- | `raise_error:` |`false`, `true` | If set to true the middleware raises `OpenapiFirst::NotFoundError` when a path or method was not found in the API description. This is useful during testing to spot an incomplete API description. | `false` (don't raise an exception)
40
- | `not_found:` | `:continue`, `:halt`| If set to `:continue` the middleware will not return 404 (405, 415), but just pass handling the request to the next middleware or application in the Rack stack. If combined with `raise_error: true` `raise_error` gets preference and an exception is raised. | `:halt` (return 4xx response)
38
+ | Name | Possible values | Description | Default |
39
+ | :------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
40
+ | `spec:` | | The spec loaded via `OpenapiFirst.load` | |
41
+ | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::NotFoundError` when a path or method was not found in the API description. This is useful during testing to spot an incomplete API description. | `false` (don't raise an exception) |
42
+ | `not_found:` | `:continue`, `:halt` | If set to `:continue` the middleware will not return 404 (405, 415), but just pass handling the request to the next middleware or application in the Rack stack. If combined with `raise_error: true` `raise_error` gets preference and an exception is raised. | `:halt` (return 4xx response) |
41
43
 
42
44
  ## OpenapiFirst::RequestValidation
43
45
 
@@ -47,12 +49,11 @@ This middleware returns a 400 status code with a body that describes the error i
47
49
  use OpenapiFirst::RequestValidation
48
50
  ```
49
51
 
50
-
51
52
  ### Options and defaults
52
53
 
53
- | Name | Possible values | Description | Default
54
- |:---|---|---|---|
55
- | `raise_error:` |`false`, `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` instead of returning 4xx. | `false` (don't raise an exception)
54
+ | Name | Possible values | Description | Default |
55
+ | :------------- | --------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- |
56
+ | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` instead of returning 4xx. | `false` (don't raise an exception) |
56
57
 
57
58
  The error responses conform with [JSON:API](https://jsonapi.org).
58
59
 
@@ -110,17 +111,18 @@ Response validation fails if response body includes a property with `writeOnly:
110
111
  This Rack endpoint maps the HTTP request to a method call based on the [operationId](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operation-object) in your API description and calls it. Responder also adds a content-type to the response.
111
112
 
112
113
  ```ruby
113
- run OpenapiFirst::Responder, spec: OpenapiFirst.load('./openapi/openapi.yaml')
114
+ run OpenapiFirst::Responder
114
115
  ```
115
116
 
116
117
  ### Options
117
- | Name | Description
118
- |:---|---|
119
- | `namespace:` | Optional. A class or module where to find the handler method. |
120
- | `resolver:` | Optional. An object that responds to `#call(operation)` and returns a (handler)[#handler]. By default this is an instance of [DefaultOperationResolver](#OpenapiFirst::DefaultOperationResolver) |
121
118
 
119
+ | Name | Description |
120
+ | :----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
121
+ | `namespace:` | Optional. A class or module where to find the handler method. |
122
+ | `resolver:` | Optional. An object that responds to `#call(operation)` and returns a [handler](#handlers). By default this is an instance of [DefaultOperationResolver](#OpenapiFirst::DefaultOperationResolver) |
122
123
 
123
124
  ### OpenapiFirst::DefaultOperationResolver
125
+
124
126
  This is the default way to look up a handler method for an operation. Handlers are always looked up in a namespace module that needs to be specified.
125
127
 
126
128
  It works like this:
@@ -144,13 +146,15 @@ There are two ways to set the response body:
144
146
  - Returning a value which will get converted to JSON
145
147
 
146
148
  ## OpenapiFirst::ResponseValidation
147
- This middleware is especially useful when testing. It *always* raises an error if the response is not valid.
149
+
150
+ This middleware is especially useful when testing. It _always_ raises an error if the response is not valid.
148
151
 
149
152
  ```ruby
150
153
  use OpenapiFirst::ResponseValidation if ENV['RACK_ENV'] == 'test'
151
154
  ```
152
155
 
153
156
  ## Standalone usage
157
+
154
158
  Instead of composing these middlewares yourself you can use `OpenapiFirst.app`.
155
159
 
156
160
  ```ruby
@@ -181,15 +185,14 @@ The above will use the mentioned Rack middlewares to:
181
185
 
182
186
  ### Options and defaults
183
187
 
184
- | Name | Possible values | Description | Default
185
- |:---|---|---|---|
186
- | `spec_path` || A filepath to an OpenAPI definition file. |
187
- | `namespace:` || A class or module where to find the handler methods.|
188
- | `response_validation:` | `true`, `false` | If set to true it raises an exception if the response is invalid. This is useful during testing. | `false`
189
- | `router_raise_error:` | `true`, `false` | If set to true it raises an exception (subclass of `OpenapiFirst::Error` when a request path/method is not specified. This is useful during testing. | `false`
190
- | `request_validation_raise_error:` | `true`, `false` | If set to true it raises an exception (subclass of `OpenapiFirst::Error` when a request is not valid. | `false`
191
- | `resolver:` | | Option to customize finding the [handler](#handler) method for an operation. See [OpenapiFirst::Responder](#OpenapiFirst::Responder) for details.
192
-
188
+ | Name | Possible values | Description | Default |
189
+ | :-------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
190
+ | `spec_path` | | A filepath to an OpenAPI definition file. |
191
+ | `namespace:` | | A class or module where to find the handler methods. |
192
+ | `response_validation:` | `true`, `false` | If set to true it raises an exception if the response is invalid. This is useful during testing. | `false` |
193
+ | `router_raise_error:` | `true`, `false` | If set to true it raises an exception (subclass of `OpenapiFirst::Error` when a request path/method is not specified. This is useful during testing. | `false` |
194
+ | `request_validation_raise_error:` | `true`, `false` | If set to true it raises an exception (subclass of `OpenapiFirst::Error` when a request is not valid. | `false` |
195
+ | `resolver:` | | Option to customize finding the [handler](#handlers) method for an operation. See [OpenapiFirst::Responder](#OpenapiFirst::Responder) for details. |
193
196
 
194
197
  Handler functions (`find_pet`) are called with two arguments:
195
198
 
@@ -289,6 +292,10 @@ Run `bundle exec rspec` to run the tests.
289
292
 
290
293
  See `bundle exec rake -T` for rubygems related tasks.
291
294
 
295
+ ## Benchmarks
296
+
297
+ [Results](https://gist.github.com/ahx/e6ffced58bd2e8d5baffb2f4d2c1f823)
298
+
292
299
  ### Run benchmarks
293
300
 
294
301
  ```sh
data/benchmarks/Gemfile CHANGED
@@ -7,7 +7,7 @@ gem 'benchmark-memory'
7
7
  gem 'committee'
8
8
  gem 'grape'
9
9
  gem 'hanami-api'
10
- gem 'hanami-router', '~> 2.0.0.alpha3'
10
+ gem 'hanami-router', '~> 2.0.0.alpha5'
11
11
  gem 'multi_json'
12
12
  gem 'openapi_first', path: '../'
13
13
  gem 'sinatra'
@@ -1,42 +1,39 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- openapi_first (0.14.0)
4
+ openapi_first (0.15.0)
5
5
  deep_merge (>= 1.2.1)
6
- hanami-router (~> 2.0.alpha3)
7
- hanami-utils (~> 2.0.alpha1)
6
+ hanami-router (~> 2.0.alpha5)
7
+ hanami-utils (~> 2.0.alpha3)
8
+ json_refs (>= 0.1.7)
8
9
  json_schemer (~> 0.2.16)
9
10
  multi_json (~> 1.14)
10
- oas_parser (~> 0.25.1)
11
11
  rack (~> 2.2)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activesupport (6.1.4)
16
+ activesupport (7.0.2.2)
17
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
18
  i18n (>= 1.6, < 2)
19
19
  minitest (>= 5.1)
20
20
  tzinfo (~> 2.0)
21
- zeitwerk (~> 2.3)
22
- addressable (2.8.0)
23
- public_suffix (>= 2.0.2, < 5.0)
24
- benchmark-ips (2.9.1)
25
- benchmark-memory (0.1.2)
26
- memory_profiler (~> 0.9)
21
+ benchmark-ips (2.9.3)
22
+ benchmark-memory (0.2.0)
23
+ memory_profiler (~> 1)
27
24
  builder (3.2.4)
28
25
  committee (4.4.0)
29
26
  json_schema (~> 0.14, >= 0.14.3)
30
27
  openapi_parser (>= 0.11.1, < 1.0)
31
28
  rack (>= 1.5)
32
29
  concurrent-ruby (1.1.9)
33
- deep_merge (1.2.1)
34
- dry-configurable (0.12.1)
30
+ deep_merge (1.2.2)
31
+ dry-configurable (0.14.0)
35
32
  concurrent-ruby (~> 1.0)
36
- dry-core (~> 0.5, >= 0.5.0)
37
- dry-container (0.8.0)
33
+ dry-core (~> 0.6)
34
+ dry-container (0.9.0)
38
35
  concurrent-ruby (~> 1.0)
39
- dry-configurable (~> 0.1, >= 0.1.3)
36
+ dry-configurable (~> 0.13, >= 0.13.0)
40
37
  dry-core (0.7.1)
41
38
  concurrent-ruby (~> 1.0)
42
39
  dry-inflector (0.2.1)
@@ -50,9 +47,9 @@ GEM
50
47
  dry-core (~> 0.5, >= 0.5)
51
48
  dry-inflector (~> 0.1, >= 0.1.2)
52
49
  dry-logic (~> 1.0, >= 1.0.2)
53
- ecma-re-validator (0.3.0)
54
- regexp_parser (~> 2.0)
55
- grape (1.5.3)
50
+ ecma-re-validator (0.4.0)
51
+ regexp_parser (~> 2.2)
52
+ grape (1.6.2)
56
53
  activesupport
57
54
  builder
58
55
  dry-types (>= 1.1)
@@ -66,22 +63,22 @@ GEM
66
63
  mustermann (~> 1.0)
67
64
  mustermann-contrib (~> 1.0)
68
65
  rack (~> 2.0)
69
- hanami-utils (2.0.0.alpha2)
66
+ hanami-utils (2.0.0.alpha6)
70
67
  concurrent-ruby (~> 1.0)
71
68
  dry-transformer (~> 0.1)
72
69
  hansi (0.2.0)
73
- hash-deep-merge (0.1.1)
74
- i18n (1.8.10)
70
+ i18n (1.9.1)
75
71
  concurrent-ruby (~> 1.0)
72
+ json_refs (0.1.7)
73
+ hana
76
74
  json_schema (0.21.0)
77
75
  json_schemer (0.2.18)
78
76
  ecma-re-validator (~> 0.3)
79
77
  hana (~> 1.3)
80
78
  regexp_parser (~> 2.0)
81
79
  uri_template (~> 0.7)
82
- memory_profiler (0.9.14)
83
- mini_portile2 (2.6.1)
84
- minitest (5.14.4)
80
+ memory_profiler (1.0.0)
81
+ minitest (5.15.0)
85
82
  multi_json (1.15.0)
86
83
  mustermann (1.1.1)
87
84
  ruby2_keywords (~> 0.0.1)
@@ -90,26 +87,13 @@ GEM
90
87
  mustermann (= 1.1.1)
91
88
  mustermann-grape (1.0.1)
92
89
  mustermann (>= 1.0.0)
93
- nokogiri (1.12.2)
94
- mini_portile2 (~> 2.6.1)
95
- racc (~> 1.4)
96
- oas_parser (0.25.4)
97
- activesupport (>= 4.0.0)
98
- addressable (~> 2.3)
99
- builder (~> 3.2.3)
100
- deep_merge (~> 1.2.1)
101
- hash-deep-merge
102
- mustermann-contrib (~> 1.1.1)
103
- nokogiri
104
- openapi_parser (0.14.1)
105
- public_suffix (4.0.6)
106
- racc (1.5.2)
90
+ openapi_parser (0.15.0)
107
91
  rack (2.2.3)
108
92
  rack-accept (0.4.5)
109
93
  rack (>= 0.4)
110
94
  rack-protection (2.1.0)
111
95
  rack
112
- regexp_parser (2.1.1)
96
+ regexp_parser (2.2.1)
113
97
  ruby2_keywords (0.0.5)
114
98
  seg (1.2.0)
115
99
  sinatra (2.1.0)
@@ -124,10 +108,9 @@ GEM
124
108
  tzinfo (2.0.4)
125
109
  concurrent-ruby (~> 1.0)
126
110
  uri_template (0.7.0)
127
- zeitwerk (2.4.2)
128
111
 
129
112
  PLATFORMS
130
- ruby
113
+ x86_64-darwin-20
131
114
 
132
115
  DEPENDENCIES
133
116
  benchmark-ips
@@ -135,11 +118,11 @@ DEPENDENCIES
135
118
  committee
136
119
  grape
137
120
  hanami-api
138
- hanami-router (~> 2.0.0.alpha3)
121
+ hanami-router (~> 2.0.0.alpha5)
139
122
  multi_json
140
123
  openapi_first!
141
124
  sinatra
142
125
  syro
143
126
 
144
127
  BUNDLED WITH
145
- 2.2.3
128
+ 2.2.28
@@ -20,7 +20,7 @@ app = Class.new(Hanami::API) do
20
20
  end.new
21
21
 
22
22
  use Committee::Middleware::RequestValidation,
23
- schema_path: './apps/openapi.yaml',
23
+ schema_path: File.absolute_path('./openapi.yaml', __dir__),
24
24
  parse_response_by_content_type: true
25
25
 
26
26
  run app
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'committee'
5
+ require 'hanami/api'
6
+
7
+ app = Class.new(Hanami::API) do
8
+ get '/hello/:id' do
9
+ json(hello: 'world', id: params.fetch(:id))
10
+ end
11
+
12
+ get '/hello' do
13
+ json([{ hello: 'world' }])
14
+ end
15
+
16
+ post '/hello' do
17
+ status 201
18
+ json(hello: 'world')
19
+ end
20
+ end.new
21
+
22
+ use Committee::Middleware::RequestValidation,
23
+ schema_path: File.absolute_path('./openapi.yaml', __dir__),
24
+ parse_response_by_content_type: true
25
+
26
+ use Committee::Middleware::ResponseValidation,
27
+ schema_path: File.absolute_path('./openapi.yaml', __dir__)
28
+
29
+ run app
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'committee'
5
+ require 'sinatra'
6
+
7
+ class SinatraWithCommiteeExample < Sinatra::Base
8
+ set :environment, :production
9
+
10
+ get '/hello/:id' do
11
+ content_type :json
12
+ MultiJson.dump(hello: 'world', id: params.fetch('id'))
13
+ end
14
+
15
+ get '/hello' do
16
+ content_type :json
17
+ MultiJson.dump([{ hello: 'world' }])
18
+ end
19
+
20
+ post '/hello' do
21
+ content_type :json
22
+ status 201
23
+ MultiJson.dump(hello: 'world')
24
+ end
25
+ end
26
+
27
+ use Committee::Middleware::RequestValidation,
28
+ schema_path: File.absolute_path('./openapi.yaml', __dir__),
29
+ parse_response_by_content_type: true
30
+
31
+ run SinatraWithCommiteeExample
@@ -28,15 +28,13 @@ paths:
28
28
  content:
29
29
  application/json:
30
30
  schema:
31
- type: array
32
- items:
33
- type: object
34
- required: [hello, id]
35
- properties:
36
- hello:
37
- type: string
38
- id:
39
- type: string
31
+ type: object
32
+ required: [hello, id]
33
+ properties:
34
+ hello:
35
+ type: string
36
+ id:
37
+ type: string
40
38
  /hello:
41
39
  get:
42
40
  operationId: find_things
@@ -61,11 +59,13 @@ paths:
61
59
  content:
62
60
  application/json:
63
61
  schema:
64
- type: object
65
- required: [hello]
66
- properties:
67
- hello:
68
- type: string
62
+ type: array
63
+ items:
64
+ type: object
65
+ required: [hello]
66
+ properties:
67
+ hello:
68
+ type: string
69
69
  default:
70
70
  description: Error response
71
71
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'openapi_first'
5
+ require 'hanami/api'
6
+
7
+ app = Class.new(Hanami::API) do
8
+ get '/hello/:id' do
9
+ json(hello: 'world', id: params.fetch(:id))
10
+ end
11
+
12
+ get '/hello' do
13
+ json([{ hello: 'world' }])
14
+ end
15
+
16
+ post '/hello' do
17
+ status 201
18
+ json(hello: 'world')
19
+ end
20
+ end.new
21
+
22
+ oas_path = File.absolute_path('./openapi.yaml', __dir__)
23
+ use OpenapiFirst::Router, spec: OpenapiFirst.load(oas_path)
24
+ use OpenapiFirst::RequestValidation
25
+
26
+ run app
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'openapi_first'
5
+
6
+ namespace = Module.new do
7
+ def self.find_thing(params, _res)
8
+ { hello: 'world', id: params.fetch(:id) }
9
+ end
10
+
11
+ def self.find_things(_params, _res)
12
+ [{ hello: 'world' }]
13
+ end
14
+
15
+ def self.create_thing(_params, res)
16
+ res.status = 201
17
+ { hello: 'world' }
18
+ end
19
+ end
20
+
21
+ oas_path = File.absolute_path('./openapi.yaml', __dir__)
22
+ run OpenapiFirst.app(oas_path, namespace: namespace, response_validation: true)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rack'
4
- require 'logger'
5
4
 
6
5
  module OpenapiFirst
7
6
  class App
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
- require 'json_schemer'
4
+ require 'set'
5
5
  require_relative 'schema_validation'
6
6
  require_relative 'utils'
7
7
  require_relative 'response_object'
@@ -118,7 +118,7 @@ module OpenapiFirst
118
118
  end
119
119
 
120
120
  def all_parameters
121
- parameters = @path_item_object['parameters'] || []
121
+ parameters = @path_item_object['parameters']&.dup || []
122
122
  parameters_on_operation = operation_object['parameters']
123
123
  parameters.concat(parameters_on_operation) if parameters_on_operation
124
124
  parameters
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rack'
4
- require 'json_schemer'
5
4
  require 'multi_json'
6
5
  require_relative 'inbox'
7
6
  require_relative 'router_required'
@@ -106,8 +105,10 @@ module OpenapiFirst
106
105
  return unless schema
107
106
 
108
107
  params = filtered_params(schema.raw_schema, params)
109
- errors = schema.validate(Utils.deep_stringify(params))
108
+ params = Utils.deep_stringify(params)
109
+ errors = schema.validate(params)
110
110
  halt_with_error(400, serialize_query_parameter_errors(errors)) if errors.any?
111
+ params = Utils.deep_symbolize(params)
111
112
  env[PARAMETERS] = params
112
113
  env[INBOX].merge! params
113
114
  end
@@ -142,6 +143,8 @@ module OpenapiFirst
142
143
  end
143
144
 
144
145
  def parse_array_parameter(value, schema)
146
+ return value if value.nil? || value.empty?
147
+
145
148
  array = value.is_a?(Array) ? value : value.split(',')
146
149
  return array unless schema['items']
147
150
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rack'
4
+ require 'multi_json'
4
5
  require_relative 'inbox'
5
6
  require_relative 'default_operation_resolver'
6
7
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
- require_relative 'utils'
5
4
 
6
5
  module OpenapiFirst
7
6
  # Represents an OpenAPI Response Object
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json_schemer'
4
3
  require 'multi_json'
5
4
  require_relative 'router_required'
6
- require_relative 'validation'
5
+ require_relative 'validation_format'
7
6
 
8
7
  module OpenapiFirst
9
8
  class ResponseValidation
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json_schemer'
4
- require 'multi_json'
5
- require_relative 'validation'
3
+ require_relative 'response_validation'
6
4
  require_relative 'router'
7
5
 
8
6
  module OpenapiFirst
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'rack'
4
4
  require 'hanami/router'
5
- require_relative 'utils'
6
5
 
7
6
  module OpenapiFirst
8
7
  class Router
@@ -14,6 +14,7 @@ module OpenapiFirst
14
14
  @schemer = JSONSchemer.schema(
15
15
  schema,
16
16
  keywords: custom_keywords,
17
+ insert_property_defaults: true,
17
18
  before_property_validation: proc do |data, property, property_schema, parent|
18
19
  convert_nullable(data, property, property_schema, parent)
19
20
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '0.14.0'
4
+ VERSION = '0.15.0'
5
5
  end
data/lib/openapi_first.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
- require 'oas_parser'
5
- require 'openapi_first/definition'
6
- require 'openapi_first/version'
7
- require 'openapi_first/inbox'
8
- require 'openapi_first/router'
9
- require 'openapi_first/request_validation'
10
- require 'openapi_first/response_validator'
11
- require 'openapi_first/response_validation'
12
- require 'openapi_first/responder'
13
- require 'openapi_first/app'
4
+ require 'json_refs'
5
+ require_relative 'openapi_first/definition'
6
+ require_relative 'openapi_first/version'
7
+ require_relative 'openapi_first/inbox'
8
+ require_relative 'openapi_first/router'
9
+ require_relative 'openapi_first/request_validation'
10
+ require_relative 'openapi_first/response_validator'
11
+ require_relative 'openapi_first/response_validation'
12
+ require_relative 'openapi_first/responder'
13
+ require_relative 'openapi_first/app'
14
14
 
15
15
  module OpenapiFirst
16
16
  OPERATION = 'openapi_first.operation'
@@ -24,8 +24,10 @@ module OpenapiFirst
24
24
  end
25
25
 
26
26
  def self.load(spec_path, only: nil)
27
- content = YAML.load_file(spec_path)
28
- resolved = OasParser::Parser.new(spec_path, content).resolve
27
+ resolved = Dir.chdir(File.dirname(spec_path)) do
28
+ content = YAML.load_file(File.basename(spec_path))
29
+ JsonRefs.call(content, resolve_local_ref: true, resolve_file_ref: true)
30
+ end
29
31
  resolved['paths'].filter!(&->(key, _) { only.call(key) }) if only
30
32
  Definition.new(resolved, spec_path)
31
33
  end
@@ -35,15 +35,18 @@ Gem::Specification.new do |spec|
35
35
  spec.required_ruby_version = '>= 2.6.0'
36
36
 
37
37
  spec.add_runtime_dependency 'deep_merge', '>= 1.2.1'
38
- spec.add_runtime_dependency 'hanami-router', '~> 2.0.alpha3'
39
- spec.add_runtime_dependency 'hanami-utils', '~> 2.0.alpha1'
38
+ spec.add_runtime_dependency 'hanami-router', '~> 2.0.alpha5'
39
+ spec.add_runtime_dependency 'hanami-utils', '~> 2.0.alpha3'
40
+ spec.add_runtime_dependency 'json_refs', '>= 0.1.7'
40
41
  spec.add_runtime_dependency 'json_schemer', '~> 0.2.16'
41
42
  spec.add_runtime_dependency 'multi_json', '~> 1.14'
42
- spec.add_runtime_dependency 'oas_parser', '~> 0.25.1'
43
43
  spec.add_runtime_dependency 'rack', '~> 2.2'
44
44
 
45
45
  spec.add_development_dependency 'bundler', '~> 2'
46
46
  spec.add_development_dependency 'rack-test', '~> 1'
47
47
  spec.add_development_dependency 'rake', '~> 13'
48
48
  spec.add_development_dependency 'rspec', '~> 3'
49
+ spec.metadata = {
50
+ 'rubygems_mfa_required' => 'true'
51
+ }
49
52
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-08 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merge
@@ -30,70 +30,70 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.0.alpha3
33
+ version: 2.0.alpha5
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 2.0.alpha3
40
+ version: 2.0.alpha5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hanami-utils
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.0.alpha1
47
+ version: 2.0.alpha3
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.0.alpha1
54
+ version: 2.0.alpha3
55
55
  - !ruby/object:Gem::Dependency
56
- name: json_schemer
56
+ name: json_refs
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.2.16
61
+ version: 0.1.7
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 0.2.16
68
+ version: 0.1.7
69
69
  - !ruby/object:Gem::Dependency
70
- name: multi_json
70
+ name: json_schemer
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.14'
75
+ version: 0.2.16
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.14'
82
+ version: 0.2.16
83
83
  - !ruby/object:Gem::Dependency
84
- name: oas_parser
84
+ name: multi_json
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.25.1
89
+ version: '1.14'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.25.1
96
+ version: '1.14'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rack
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -176,7 +176,6 @@ files:
176
176
  - ".gitignore"
177
177
  - ".rspec"
178
178
  - ".rubocop.yml"
179
- - ".travis.yml"
180
179
  - CHANGELOG.md
181
180
  - Gemfile
182
181
  - Gemfile.lock
@@ -186,11 +185,15 @@ files:
186
185
  - benchmarks/Gemfile
187
186
  - benchmarks/Gemfile.lock
188
187
  - benchmarks/apps/committee.ru
188
+ - benchmarks/apps/committee_with_response_validation.ru
189
+ - benchmarks/apps/committee_with_sinatra.ru
189
190
  - benchmarks/apps/grape.ru
190
191
  - benchmarks/apps/hanami_api.ru
191
192
  - benchmarks/apps/hanami_router.ru
192
193
  - benchmarks/apps/openapi.yaml
193
194
  - benchmarks/apps/openapi_first.ru
195
+ - benchmarks/apps/openapi_first_with_hanami_api.ru
196
+ - benchmarks/apps/openapi_first_with_response_validation.ru
194
197
  - benchmarks/apps/sinatra.ru
195
198
  - benchmarks/apps/syro.ru
196
199
  - benchmarks/benchmarks.rb
@@ -224,9 +227,7 @@ homepage: https://github.com/ahx/openapi_first
224
227
  licenses:
225
228
  - MIT
226
229
  metadata:
227
- https://github.com/ahx/openapi_first: https://github.com/ahx/openapi_first
228
- source_code_uri: https://github.com/ahx/openapi_first
229
- changelog_uri: https://github.com/ahx/openapi_first/blob/master/CHANGELOG.md
230
+ rubygems_mfa_required: 'true'
230
231
  post_install_message:
231
232
  rdoc_options: []
232
233
  require_paths:
@@ -242,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
243
  - !ruby/object:Gem::Version
243
244
  version: '0'
244
245
  requirements: []
245
- rubygems_version: 3.2.3
246
+ rubygems_version: 3.3.3
246
247
  signing_key:
247
248
  specification_version: 4
248
249
  summary: Implement REST APIs based on OpenApi.
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.7.0
7
- before_install: gem install bundler -v 2.1.4
8
- install: bundle install --jobs=3 --retry=3