openapi_first 0.21.0 → 1.0.0.beta3

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