openapi_first 0.21.0 → 1.0.0.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b8b03aaa251de1bdb5cbba71de089bf1ffc6b9dbb96512008f88e783c3cea27
4
- data.tar.gz: 02eb6cec864e9b5ed272d4392b31fd9e006713d3a8b00df9b26e9a52fa68e555
3
+ metadata.gz: 800354f7ac2847fb16987e6961589aaebb84c161f3b76ea652a00a4cf8762fbe
4
+ data.tar.gz: f443b72fa8ce1103bfc5a7b30367ce96f84e0dc7ad137722424cab0ac0c13357
5
5
  SHA512:
6
- metadata.gz: e37e99e982f0ead9d54587683fa74491e69998f520b1cfb4993c9e1ee81273537dfdf1751c77daef856ab3c3051660589d2f8ac6e58508fd11d3ea130734d2a5
7
- data.tar.gz: 6944ae2444da29928eeb12e70326505aa154f1c36a09f033083098b1e34be766b075257fd2459b94574370fa8cc417ef488f74dafcec6026eaab07a47f471445
6
+ metadata.gz: e454ee38c95a21915869e5feae0f38f65e0aa9a0a5001b6b752043fa379836164af1bf7eac9bcff192822d66053dda00d6dfa787296cce82bccf346d218f4c6c
7
+ data.tar.gz: 11a0a0ac1e1bbd350d1edfe1dcae4ccae15bcfe2f1863320f30f554c3ad16934b07891c578225d2d7d128c3cb7dafd4093407c1c153713567db4db3d9c99c938
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.0.beta3
6
+
7
+ - Remove obsolete dependency: deep_merge
8
+ - Remove obsolete dependency: hanami-utils
9
+
10
+ ## 1.0.0.beta2
11
+ - Fixed dependencies. Remove unused code.
12
+
13
+ ## 1.0.0.beta1
14
+ - Removed: `OpenapiFirst::Responder` and `OpenapiFirst::RackResponder`
15
+ - Removed: `OpenapiFirst.app` and `OpenapiFirst.middleware`
16
+ - Removed: `OpenapiFirst::Coverage`
17
+ - Breaking: Parsed query and path parameters are available at `env[OpenapiFirst::PARAMS]`(or `env['openapi.params']`) instead of `OpenapiFirst::PARAMETERS`.
18
+ - Breaking: Request body and parameters now use string keys instead of symbols!
19
+ - Breaking: Query parameters are now parsed exactly like in the API description via the openapi_parameters gem. This means a couple of things:
20
+ - Query parameters now support `explode: true` (default) and `explode: false` for array and object parameters.
21
+ - Query parameters with brackets like 'filter[tag]' are no longer deconstructed into nested hashes, but accessible via the `filter[tag]` key.
22
+ - Query parameters are no longer interpreted as `style: deepObject` by default. If you want to use `style: deepObject`, for example to pass a nested hash as a query parameter like `filter[tag]`, you have to set `style: deepObject` explicitly.
23
+ - Path parameters are now parsed exactly as in the API description via the openapi_parameters gem.
24
+
5
25
  ## 0.21.0
6
26
 
7
27
  - Fix: Query parameter validation does not fail if header parameters are defined (Thanks to [JF Lalonde](https://github.com/JF-Lalonde))
data/Gemfile.lock CHANGED
@@ -1,28 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openapi_first (0.21.0)
5
- deep_merge (>= 1.2.1)
4
+ openapi_first (1.0.0.beta3)
6
5
  hanami-router (~> 2.0.0)
7
- hanami-utils (~> 2.0.0)
8
6
  json_refs (~> 0.1, >= 0.1.7)
9
7
  json_schemer (~> 0.2.16)
10
8
  multi_json (~> 1.14)
11
- rack (~> 2.2)
9
+ openapi_parameters (~> 0.2)
10
+ rack (>= 2.2, < 4.0)
12
11
 
13
12
  GEM
14
13
  remote: https://rubygems.org/
15
14
  specs:
16
15
  ast (2.4.2)
17
16
  coderay (1.1.3)
18
- concurrent-ruby (1.2.2)
19
- deep_merge (1.2.2)
20
17
  diff-lcs (1.5.0)
21
- dry-core (1.0.0)
22
- concurrent-ruby (~> 1.0)
23
- zeitwerk (~> 2.6)
24
- dry-transformer (1.0.1)
25
- zeitwerk (~> 2.6)
26
18
  ecma-re-validator (0.4.0)
27
19
  regexp_parser (~> 2.2)
28
20
  hana (1.3.7)
@@ -30,10 +22,6 @@ GEM
30
22
  mustermann (~> 3.0)
31
23
  mustermann-contrib (~> 3.0)
32
24
  rack (~> 2.0)
33
- hanami-utils (2.0.3)
34
- concurrent-ruby (~> 1.0)
35
- dry-core (~> 1.0, < 2)
36
- dry-transformer (~> 1.0, < 2)
37
25
  hansi (0.2.1)
38
26
  json (2.6.3)
39
27
  json_refs (0.1.7)
@@ -50,13 +38,16 @@ GEM
50
38
  mustermann-contrib (3.0.0)
51
39
  hansi (~> 0.2.0)
52
40
  mustermann (= 3.0.0)
41
+ openapi_parameters (0.2.1)
42
+ rack (>= 2.2)
43
+ zeitwerk (~> 2.6)
53
44
  parallel (1.22.1)
54
- parser (3.2.1.0)
45
+ parser (3.2.1.1)
55
46
  ast (~> 2.4.1)
56
47
  pry (0.14.2)
57
48
  coderay (~> 1.1)
58
49
  method_source (~> 1.0)
59
- rack (2.2.6.2)
50
+ rack (2.2.6.4)
60
51
  rack-test (1.1.0)
61
52
  rack (>= 1.0, < 3)
62
53
  rainbow (3.1.1)
@@ -72,23 +63,23 @@ GEM
72
63
  rspec-expectations (3.12.2)
73
64
  diff-lcs (>= 1.2.0, < 2.0)
74
65
  rspec-support (~> 3.12.0)
75
- rspec-mocks (3.12.3)
66
+ rspec-mocks (3.12.5)
76
67
  diff-lcs (>= 1.2.0, < 2.0)
77
68
  rspec-support (~> 3.12.0)
78
69
  rspec-support (3.12.0)
79
- rubocop (1.45.1)
70
+ rubocop (1.48.1)
80
71
  json (~> 2.3)
81
72
  parallel (~> 1.10)
82
73
  parser (>= 3.2.0.0)
83
74
  rainbow (>= 2.2.2, < 4.0)
84
75
  regexp_parser (>= 1.8, < 3.0)
85
76
  rexml (>= 3.2.5, < 4.0)
86
- rubocop-ast (>= 1.24.1, < 2.0)
77
+ rubocop-ast (>= 1.26.0, < 2.0)
87
78
  ruby-progressbar (~> 1.7)
88
79
  unicode-display_width (>= 2.4.0, < 3.0)
89
- rubocop-ast (1.26.0)
80
+ rubocop-ast (1.28.0)
90
81
  parser (>= 3.2.1.0)
91
- ruby-progressbar (1.11.0)
82
+ ruby-progressbar (1.13.0)
92
83
  ruby2_keywords (0.0.5)
93
84
  unicode-display_width (2.4.2)
94
85
  uri_template (0.7.0)
@@ -96,8 +87,6 @@ GEM
96
87
 
97
88
  PLATFORMS
98
89
  arm64-darwin-21
99
- x86_64-darwin-20
100
- x86_64-linux
101
90
 
102
91
  DEPENDENCIES
103
92
  bundler (~> 2)
@@ -109,4 +98,4 @@ DEPENDENCIES
109
98
  rubocop
110
99
 
111
100
  BUNDLED WITH
112
- 2.3.7
101
+ 2.3.10
data/README.md CHANGED
@@ -2,39 +2,27 @@
2
2
 
3
3
  [![Join the chat at https://gitter.im/openapi_first/community](https://badges.gitter.im/openapi_first/community.svg)](https://gitter.im/openapi_first/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
4
 
5
- OpenapiFirst helps to implement HTTP APIs based on an [OpenApi](https://www.openapis.org/) API description. The idea is that you create an API description first, then add code that returns data and implements your business logic and be done.
5
+ OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description.
6
6
 
7
- Start with writing an OpenAPI file that describes the API, which you are about to implement. Use a [validator](https://github.com/stoplightio/spectral/) to make sure the file is valid.
7
+ It provides these Rack middlewares:
8
8
 
9
- You can use OpenapiFirst via its [Rack middlewares](#rack-middlewares) or in [standalone mode](#standalone-usage).
9
+ - [`OpenapiFirst::RequestValidation`](#request-validation) Validates the request against the API description and returns 400 if the request is invalid.
10
+ - [`OpenapiFirst::ResponseValidation`](#response-validation) Validates the response and raises an exception if the response body is invalid.
11
+ - [`OpenapiFirst::Router`](#openapifirstrouter) – This internal middleware is added automatically when using request/response validation. It adds the OpenAPI operation for the current request to the Rack env.
10
12
 
11
- ## Alternatives
12
-
13
- This gem is inspired by [committee](https://github.com/interagent/committee) (Ruby) and [connexion](https://github.com/zalando/connexion) (Python).
14
-
15
- Here's a [comparison between committee and openapi_first](https://gist.github.com/ahx/1538c31f0652f459861713b5259e366a).
16
-
17
- ## Rack middlewares
18
-
19
- OpenapiFirst consists of these Rack middlewares:
20
-
21
- - [`OpenapiFirst::RequestValidation`](#OpenapiFirst::RequestValidation) – Validates the request against the API description and returns 400 if the request is invalid.
22
- - [`OpenapiFirst::ResponseValidation`](#OpenapiFirst::ResponseValidation) Validates the response and raises an exception if the response body is invalid.
23
- - [`OpenapiFirst::Router`](#OpenapiFirst::Router) – This internal middleware is added automatically before request/response validation. Finds the OpenAPI operation for the current request or returns 404 if no operation was found. This can be customized by adding it yourself.
24
-
25
-
26
- And these Rack apps:
27
- - [`OpenapiFirst::Responder`](#OpenapiFirst::Responder) calls the [handler](#handlers) found for the operation, sets the correct content-type and serializes the response body to json if needed.
28
- - [`OpenapiFirst::RackResponder`](#OpenapiFirst::RackResponder) calls the [handler](#handlers) found for the operation as a normal Rack application (`call(env)`) and returns the result as is.
13
+ ## Request Validation
29
14
 
30
- ## OpenapiFirst::RequestValidation
31
-
32
- This middleware returns a 400 status code with a body that describes the error if the request is not valid.
15
+ The `OpenapiFirst::RequestValidation` middleware returns a 400 status code with a body that describes the error if the request is not valid.
33
16
 
34
17
  ```ruby
35
18
  use OpenapiFirst::RequestValidation, spec: 'openapi.yaml'
36
19
  ```
37
20
 
21
+ It adds these fields to the Rack env:
22
+ - `env[OpenapiFirst::PARAMS]` – The parsed parameters (query, path) for the current request (string keyed)
23
+ - `env[OpenapiFirst::REQUEST_BODY]` – The parsed request body (string keyed)
24
+ - `env[OpenapiFirst::OPERATION]` (Added via Router) – The Operation object for the current request. This is an instance of `OpenapiFirst::Operation`.
25
+
38
26
  ### Options and defaults
39
27
 
40
28
  | Name | Possible values | Description | Default |
@@ -62,26 +50,27 @@ content-type: "application/vnd.api+json"
62
50
  }
63
51
  ```
64
52
 
65
- This middleware adds `env[OpenapiFirst::INBOX]` which holds the (filtered) path and query parameters and the parsed request body.
66
-
67
- ### Parameter validation
53
+ ### Parameters
68
54
 
69
- The middleware filteres all top-level query parameters and paths parameters and tries to convert numeric values. Meaning, if you have an `:something_id` path with `type: integer`, it will try convert the value to an integer.
55
+ The `RequestValidation` middleware adds `env[OpenapiFirst::PARAMS]` (or `env['openapi.params']` ) with the converted query and path parameters. This only includes the parameters that are defined in the API description. It supports every [`style` and `explode` value as described](https://spec.openapis.org/oas/latest.html#style-examples) in the OpenAPI 3.0 and 3.1 specs. So you can do things these:
70
56
 
71
- It just works with a parameter with `name: filter[age]`.
72
-
73
- OpenapiFirst also supports `type: array` for query parameters and will convert `items` just as described above. [`style`](http://spec.openapis.org/oas/v3.0.3#style-values) and `explode` attributes are not supported for query parameters. It will always act as if `style: form` and `explode: false` were used for query parameters.
57
+ ```ruby
58
+ # GET /pets/filter[id]=1,2,3
59
+ env[OpenapiFirst::PARAMS] # => { 'filter[id]' => [1,2,3] }
74
60
 
75
- Conversion is currently done only for path and query parameters, but not for the request body. OpenapiFirst currently does not convert date, date-time or time formats.
61
+ # GET /colors/.blue.black.brown?format=csv
62
+ env[OpenapiFirst::PARAMS] # => { 'color_names' => ['blue', 'black', 'brown'], 'format' => 'csv' }
76
63
 
77
- If you want to forbid _nested_ query parameters you will need to use [`additionalProperties: false`](https://json-schema.org/understanding-json-schema/reference/object.html#properties) in your query parameter JSON schema.
64
+ # And a lot more.
65
+ ```
78
66
 
79
- _OpenapiFirst always treats query parameters like [`style: deepObject`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#style-values), **but** it just works with nested objects (`filter[foo][bar]=baz`) (see [this discussion](https://github.com/OAI/OpenAPI-Specification/issues/1706))._
67
+ Integration for specific webframeworks is ongoing. Don't hesitate to create an issue with you specific needs.
80
68
 
81
69
  ### Request body validation
82
70
 
71
+ This middleware adds the parsed request body to `env[OpenapiFirst::REQUEST_BODY]`.
72
+
83
73
  The middleware will return a status `415` if the requests content type does not match or `400` if the request body is invalid.
84
- This will also add the parsed request body to `env[OpenapiFirst::REQUEST_BODY]`.
85
74
 
86
75
  ### Header, Cookie, Path parameter validation
87
76
 
@@ -93,10 +82,9 @@ Request validation fails if request includes a property with `readOnly: true`.
93
82
 
94
83
  Response validation fails if response body includes a property with `writeOnly: true`.
95
84
 
96
- ## OpenapiFirst::ResponseValidation
97
-
98
- This middleware is especially useful when testing. It _always_ raises an error if the response is not valid.
85
+ ## Response validation
99
86
 
87
+ The `OpenapiFirst::ResponseValidation` middleware is especially useful when testing. It _always_ raises an error if the response is not valid.
100
88
 
101
89
  ```ruby
102
90
  use OpenapiFirst::ResponseValidation, spec: 'openapi.yaml' if ENV['RACK_ENV'] == 'test'
@@ -110,13 +98,13 @@ use OpenapiFirst::ResponseValidation, spec: 'openapi.yaml' if ENV['RACK_ENV'] ==
110
98
 
111
99
  ## OpenapiFirst::Router
112
100
 
113
- This middleware is used automatically, but you can add it to the top of your middleware stack if you want to change configuration.
101
+ This middleware is used automatically, but you can add it to the top of your middleware stack if you want to customize the behavior via options.
114
102
 
115
103
  ```ruby
116
104
  use OpenapiFirst::Router, spec: './openapi/openapi.yaml'
117
105
  ```
118
106
 
119
- This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation object that responds to `#operation_id`, `#path` (and `#[]` to access raw fields).
107
+ This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation object that responds to `#operation_id`, `#path` (and `#[string]` to access raw fields).
120
108
 
121
109
  ### Options and defaults
122
110
 
@@ -126,115 +114,11 @@ This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation obj
126
114
  | `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) |
127
115
  | `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) |
128
116
 
129
- ## OpenapiFirst::RackResponder
130
-
131
- 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 as a normal Rack application.
132
- It does not not serialize objects as JSON or adds a content-type.
133
-
134
- ```ruby
135
- run OpenapiFirst::RackResponder
136
- ```
137
-
138
- ### Options
139
-
140
- | Name | Description |
141
- | :----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
142
- | `namespace:` | Optional. A class or module where to find the handler method. |
143
- | `resolver:` | Optional. An object that responds to `#call(operation)` and returns a [handler](#handlers). By default this is an instance of [DefaultOperationResolver](#OpenapiFirst::DefaultOperationResolver) |
144
-
145
- ## OpenapiFirst::Responder
146
-
147
- 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.
148
-
149
- ```ruby
150
- run OpenapiFirst::Responder
151
- ```
152
-
153
- ### Options
154
-
155
- | Name | Description |
156
- | :----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
157
- | `namespace:` | Optional. A class or module where to find the handler method. |
158
- | `resolver:` | Optional. An object that responds to `#call(operation)` and returns a [handler](#handlers). By default this is an instance of [DefaultOperationResolver](#OpenapiFirst::DefaultOperationResolver) |
159
-
160
- ### OpenapiFirst::DefaultOperationResolver
161
-
162
- 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.
163
-
164
- It works like this:
165
-
166
- - An operationId "create_pet" or "createPet" or "create pet" calls `MyApi.create_pet(params, response)`
167
- - "some_things.create" calls: `MyApi::SomeThings.create(params, response)`
168
- - "pets#create" instantiates the class once (`MyApi::Pets::Create.new) and calls it on every request(`instance.call(params, response)`).
169
-
170
- ### Handlers
171
-
172
- These handler methods are called with two arguments:
173
-
174
- - `params` - Holds the parsed request body, filtered query params and path parameters (same as `env[OpenapiFirst::INBOX]`)
175
- - `res` - Holds a Rack::Response that you can modify if needed
176
-
177
- You can call `params.env` to access the Rack env (just like in [Hanami actions](https://guides.hanamirb.org/actions/parameters/))
178
-
179
- There are two ways to set the response body:
180
-
181
- - Calling `res.write "things"` (see [Rack::Response](https://www.rubydoc.info/github/rack/rack/Rack/Response))
182
- - Returning a value which will get converted to JSON
183
-
184
- ## Standalone usage
185
-
186
- Instead of composing these middlewares yourself you can use `OpenapiFirst.app`.
187
-
188
- ```ruby
189
- module Pets
190
- def self.find_pet(params, res)
191
- {
192
- id: params[:id],
193
- name: 'Oscar'
194
- }
195
- end
196
- end
197
-
198
- # In config.ru:
199
- require 'openapi_first'
200
- run OpenapiFirst.app(
201
- './openapi/openapi.yaml',
202
- namespace: Pets,
203
- response_validation: ENV['RACK_ENV'] == 'test',
204
- router_raise_error: ENV['RACK_ENV'] == 'test'
205
- )
206
- ```
207
-
208
- The above will use the mentioned Rack middlewares to:
209
-
210
- - Validate the request and respond with 400 if the request does not match with your API description
211
- - Map the request to a method call `Pets.find_pet` based on the `operationId` in the API description
212
- - Set the response content type according to your spec (here with the default status code `200`)
213
-
214
- ### Options and defaults
215
-
216
- | Name | Possible values | Description | Default |
217
- | :-------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
218
- | `spec_path` | | A filepath to an OpenAPI definition file. |
219
- | `namespace:` | | A class or module where to find the handler methods. |
220
- | `response_validation:` | `true`, `false` | If set to true it raises an exception if the response is invalid. This is useful during testing. | `false` |
221
- | `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` |
222
- | `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` |
223
- | `resolver:` | | Option to customize finding the [handler](#handlers) method for an operation. See [OpenapiFirst::Responder](#OpenapiFirst::Responder) for details. |
224
-
225
- Handler functions (`find_pet`) are called with two arguments:
226
-
227
- - `params` - Holds the parsed request body, filtered query params and path parameters
228
- - `res` - Holds a Rack::Response that you can modify if needed
229
- If you want to access to plain Rack env you can call `params.env`.
230
-
231
- ## If your API description does not contain all endpoints
117
+ ## Alternatives
232
118
 
233
- ```ruby
234
- run OpenapiFirst.middleware('./openapi/openapi.yaml', namespace: Pets)
235
- ```
119
+ This gem is inspired by [committee](https://github.com/interagent/committee) (Ruby) and [connexion](https://github.com/zalando/connexion) (Python).
236
120
 
237
- Here all requests that are not part of the API description will be passed to the next app.
121
+ Here's a [comparison between committee and openapi_first](https://gist.github.com/ahx/1538c31f0652f459861713b5259e366a).
238
122
 
239
123
  ## Try it out
240
124
 
@@ -272,44 +156,6 @@ spec = OpenapiFirst.load('./openapi/openapi.yaml', only: { |path| path.starts_wi
272
156
  run OpenapiFirst.app(spec, namespace: Pets)
273
157
  ```
274
158
 
275
- ## Coverage
276
-
277
- (This is a bit experimental. Please try it out and give feedback.)
278
-
279
- `OpenapiFirst::Coverage` helps you make sure, that you have called all endpoints of your OAS file when running tests via `rack-test`.
280
-
281
- ```ruby
282
- # In your test (rspec example):
283
- require 'openapi_first/coverage'
284
-
285
- describe MyApp do
286
- include Rack::Test::Methods
287
-
288
- before(:all) do
289
- @app_wrapper = OpenapiFirst::Coverage.new(MyApp, 'petstore.yaml')
290
- end
291
-
292
- after(:all) do
293
- message = "The following paths have not been called yet: #{@app_wrapper.to_be_called}"
294
- expect(@app_wrapper.to_be_called).to be_empty
295
- end
296
-
297
- # Overwrite `#app` to make rack-test call the wrapped app
298
- def app
299
- @app_wrapper
300
- end
301
-
302
- it 'does things' do
303
- get '/i/my/stuff'
304
- # …
305
- end
306
- end
307
- ```
308
-
309
- ## Mocking
310
-
311
- Out of scope. Use [Prism](https://github.com/stoplightio/prism) or [fakeit](https://github.com/JustinFeng/fakeit).
312
-
313
159
  ## Development
314
160
 
315
161
  Run `bin/setup` to install dependencies.
@@ -1,24 +1,23 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- openapi_first (0.21.0)
5
- deep_merge (>= 1.2.1)
4
+ openapi_first (1.0.0.beta3)
6
5
  hanami-router (~> 2.0.0)
7
- hanami-utils (~> 2.0.0)
8
6
  json_refs (~> 0.1, >= 0.1.7)
9
7
  json_schemer (~> 0.2.16)
10
8
  multi_json (~> 1.14)
11
- rack (~> 2.2)
9
+ openapi_parameters (~> 0.2)
10
+ rack (>= 2.2, < 4.0)
12
11
 
13
12
  GEM
14
13
  remote: https://rubygems.org/
15
14
  specs:
16
- activesupport (7.0.4.2)
15
+ activesupport (7.0.4.3)
17
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
17
  i18n (>= 1.6, < 2)
19
18
  minitest (>= 5.1)
20
19
  tzinfo (~> 2.0)
21
- benchmark-ips (2.11.0)
20
+ benchmark-ips (2.12.0)
22
21
  benchmark-memory (0.2.0)
23
22
  memory_profiler (~> 1)
24
23
  builder (3.2.4)
@@ -26,8 +25,7 @@ GEM
26
25
  json_schema (~> 0.14, >= 0.14.3)
27
26
  openapi_parser (~> 1.0)
28
27
  rack (>= 1.5)
29
- concurrent-ruby (1.2.0)
30
- deep_merge (1.2.2)
28
+ concurrent-ruby (1.2.2)
31
29
  dry-core (1.0.0)
32
30
  concurrent-ruby (~> 1.0)
33
31
  zeitwerk (~> 2.6)
@@ -36,13 +34,11 @@ GEM
36
34
  concurrent-ruby (~> 1.0)
37
35
  dry-core (~> 1.0, < 2)
38
36
  zeitwerk (~> 2.6)
39
- dry-transformer (1.0.1)
40
- zeitwerk (~> 2.6)
41
- dry-types (1.7.0)
37
+ dry-types (1.7.1)
42
38
  concurrent-ruby (~> 1.0)
43
- dry-core (~> 1.0, < 2)
44
- dry-inflector (~> 1.0, < 2)
45
- dry-logic (>= 1.4, < 2)
39
+ dry-core (~> 1.0)
40
+ dry-inflector (~> 1.0)
41
+ dry-logic (~> 1.4)
46
42
  zeitwerk (~> 2.6)
47
43
  ecma-re-validator (0.4.0)
48
44
  regexp_parser (~> 2.2)
@@ -60,10 +56,6 @@ GEM
60
56
  mustermann (~> 3.0)
61
57
  mustermann-contrib (~> 3.0)
62
58
  rack (~> 2.0)
63
- hanami-utils (2.0.3)
64
- concurrent-ruby (~> 1.0)
65
- dry-core (~> 1.0, < 2)
66
- dry-transformer (~> 1.0, < 2)
67
59
  hansi (0.2.1)
68
60
  i18n (1.12.0)
69
61
  concurrent-ruby (~> 1.0)
@@ -76,7 +68,7 @@ GEM
76
68
  regexp_parser (~> 2.0)
77
69
  uri_template (~> 0.7)
78
70
  memory_profiler (1.0.1)
79
- minitest (5.17.0)
71
+ minitest (5.18.0)
80
72
  multi_json (1.15.0)
81
73
  mustermann (3.0.0)
82
74
  ruby2_keywords (~> 0.0.1)
@@ -85,29 +77,32 @@ GEM
85
77
  mustermann (= 3.0.0)
86
78
  mustermann-grape (1.0.2)
87
79
  mustermann (>= 1.0.0)
88
- nio4r (2.5.8)
80
+ nio4r (2.5.9)
81
+ openapi_parameters (0.2.1)
82
+ rack (>= 2.2)
83
+ zeitwerk (~> 2.6)
89
84
  openapi_parser (1.0.0)
90
- puma (6.1.0)
85
+ puma (6.2.2)
91
86
  nio4r (~> 2.0)
92
- rack (2.2.6.2)
87
+ rack (2.2.6.4)
93
88
  rack-accept (0.4.5)
94
89
  rack (>= 0.4)
95
- rack-protection (3.0.5)
90
+ rack-protection (3.0.6)
96
91
  rack
97
- regexp_parser (2.7.0)
98
- roda (3.65.0)
92
+ regexp_parser (2.8.0)
93
+ roda (3.67.0)
99
94
  rack
100
95
  ruby2_keywords (0.0.5)
101
96
  seg (1.2.0)
102
- sinatra (3.0.5)
97
+ sinatra (3.0.6)
103
98
  mustermann (~> 3.0)
104
99
  rack (~> 2.2, >= 2.2.4)
105
- rack-protection (= 3.0.5)
100
+ rack-protection (= 3.0.6)
106
101
  tilt (~> 2.0)
107
102
  syro (3.2.1)
108
103
  rack (>= 1.6.0)
109
104
  seg
110
- tilt (2.0.11)
105
+ tilt (2.1.0)
111
106
  tzinfo (2.0.6)
112
107
  concurrent-ruby (~> 1.0)
113
108
  uri_template (0.7.0)
@@ -19,7 +19,6 @@ app = Class.new(Hanami::API) do
19
19
  end
20
20
  end.new
21
21
 
22
- use OpenapiFirst::Router, spec: File.absolute_path('./openapi.yaml', __dir__)
23
- use OpenapiFirst::RequestValidation
22
+ use OpenapiFirst::RequestValidation, spec: File.absolute_path('./openapi.yaml', __dir__)
24
23
 
25
24
  run app
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'openapi_first'
5
+
6
+ app = Rack::Builder.new do
7
+ use OpenapiFirst::RequestValidation, spec: File.expand_path('./openapi.yaml', __dir__)
8
+
9
+ handlers = {
10
+ 'find_thing' => lambda do |env|
11
+ params = env[OpenapiFirst::PARAMS]
12
+ body = MultiJson.dump(hello: 'world', id: params.fetch('id'))
13
+ [200, { 'Content-Type' => 'application/json' }, [body]]
14
+ end,
15
+ 'find_things' => lambda do |_env|
16
+ body = MultiJson.dump(hello: 'world')
17
+ [200, { 'Content-Type' => 'application/json' }, [body]]
18
+ end,
19
+ 'create_thing' => lambda do |_env|
20
+ body = MultiJson.dump(hello: 'world')
21
+ [201, { 'Content-Type' => 'application/json' }, [body]]
22
+ end
23
+ }
24
+
25
+ not_found = ->(_env) { [404, {}, []] }
26
+
27
+ run lambda do |env|
28
+ handlers.fetch(env[OpenapiFirst::OPERATION]&.operation_id, not_found).call(env)
29
+ end
30
+ end
31
+
32
+ run app
@@ -2,21 +2,24 @@
2
2
 
3
3
  require 'multi_json'
4
4
  require 'openapi_first'
5
+ require 'hanami/api'
5
6
 
6
- namespace = Module.new do
7
- def self.find_thing(params, _res)
8
- { hello: 'world', id: params.fetch(:id) }
7
+ app = Class.new(Hanami::API) do
8
+ get '/hello/:id' do
9
+ json(hello: 'world', id: params.fetch(:id))
9
10
  end
10
11
 
11
- def self.find_things(_params, _res)
12
- [{ hello: 'world' }]
12
+ get '/hello' do
13
+ json([{ hello: 'world' }])
13
14
  end
14
15
 
15
- def self.create_thing(_params, res)
16
- res.status = 201
17
- { hello: 'world' }
16
+ post '/hello' do
17
+ status 201
18
+ json(hello: 'world')
18
19
  end
19
- end
20
+ end.new
20
21
 
21
- oas_path = File.absolute_path('./openapi.yaml', __dir__)
22
- run OpenapiFirst.app(oas_path, namespace: namespace, response_validation: true)
22
+ use OpenapiFirst::RequestValidation, spec: File.absolute_path('./openapi.yaml', __dir__)
23
+ use OpenapiFirst::ResponseValidation
24
+
25
+ run app
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'multi_json'
4
+ require 'openapi_first'
5
+ require 'sinatra'
6
+
7
+ class SinatraWithOpenapiFirstExample < 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 OpenapiFirst::RequestValidation, spec: File.absolute_path('./openapi.yaml', __dir__)
28
+
29
+ run SinatraWithOpenapiFirstExample