openapi_first 1.0.0.beta3 → 1.0.0.beta5

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: 800354f7ac2847fb16987e6961589aaebb84c161f3b76ea652a00a4cf8762fbe
4
- data.tar.gz: f443b72fa8ce1103bfc5a7b30367ce96f84e0dc7ad137722424cab0ac0c13357
3
+ metadata.gz: 8e6c1f8f1a6fffd91827a74f95b932bfd5be9d4a897f3704efd6313bac9e6be4
4
+ data.tar.gz: 59041cacdcb634bb25e5d23025c0f86afe97632918f1e10d6f67409d31ba5f9b
5
5
  SHA512:
6
- metadata.gz: e454ee38c95a21915869e5feae0f38f65e0aa9a0a5001b6b752043fa379836164af1bf7eac9bcff192822d66053dda00d6dfa787296cce82bccf346d218f4c6c
7
- data.tar.gz: 11a0a0ac1e1bbd350d1edfe1dcae4ccae15bcfe2f1863320f30f554c3ad16934b07891c578225d2d7d128c3cb7dafd4093407c1c153713567db4db3d9c99c938
6
+ metadata.gz: 1955264ba1b60f477123cd1bbb71a14d611d598664965548a9ebe3c6508d5ac6e205dfe971bc7c1ebe6b27da78a48f1bf5d27239c886a9b4aa7db303224e0cfc
7
+ data.tar.gz: 2f25b5944e546a6619c2be01462008d358a0a80140594b0906ca62e9b152fa97b2b8225d0c137acbe29c64b7732bbd00d3f35459cd0b771b2b38c409303adde8
@@ -1,24 +1,12 @@
1
- name: Ruby
2
-
3
- on:
4
- push:
5
- branches: [ master ]
6
- pull_request:
7
- branches: [ master ]
8
-
1
+ name: Test
2
+ on: [push, pull_request]
9
3
  jobs:
10
- build:
11
-
4
+ test:
12
5
  runs-on: ubuntu-latest
13
-
14
6
  steps:
15
- - uses: actions/checkout@v2
16
- - name: Set up Ruby 2.6
17
- uses: actions/setup-ruby@v1
7
+ - uses: actions/checkout@v3
8
+ - uses: ruby/setup-ruby@v1
18
9
  with:
19
- ruby-version: 2.6.x
20
- - name: Build and test with Rake
21
- run: |
22
- gem install bundler
23
- bundle install --jobs 4 --retry 3
24
- bundle exec rake
10
+ ruby-version: '3.1'
11
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
12
+ - run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.0.5
2
+ TargetRubyVersion: 3.1.1
3
3
  NewCops: enable
4
4
  SuggestExtensions: false
5
5
  Style/Documentation:
data/CHANGELOG.md CHANGED
@@ -2,15 +2,33 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.0.beta5
6
+
7
+ - Added: `OpenapiFirst::Config.default_options=` to set default options globally
8
+ - Added: You can define custom error responses by subclassing `OpenapiFirst::ErrorResponse` and register it via `OpenapiFirst::Plugins.register_error_response(name, MyCustomErrorResponse)`
9
+
10
+ ## 1.0.0.beta4
11
+
12
+ - Update json_schemer to version 2.0
13
+ - Breaking: Requires Ruby 3.1 or later
14
+ - Added: Parameters are available at `env[OpenapiFirst::PATH_PARAMS]`, `env[OpenapiFirst::QUERY_PARAMS]`, `env[OpenapiFirst::HEADER_PARAMS]`, `env[OpenapiFirst::COOKIE_PARAMS]` in case you need to access them separately. Merged path and query parameters are still available at `env[OpenapiFirst::PARAMS]`
15
+ - Breaking / Added: ResponseValidation now validates response headers
16
+ - Breaking / Added: RequestValidation now validates cookie, path and header parameters
17
+ - Breaking: multipart File uploads are now read and then validated
18
+ - Breaking: Remove OpenapiFirst.env method
19
+ - Breaking: Request validation returns 400 instead of 415 if request body is required, but empty
20
+
5
21
  ## 1.0.0.beta3
6
22
 
7
23
  - Remove obsolete dependency: deep_merge
8
24
  - Remove obsolete dependency: hanami-utils
9
25
 
10
26
  ## 1.0.0.beta2
27
+
11
28
  - Fixed dependencies. Remove unused code.
12
29
 
13
30
  ## 1.0.0.beta1
31
+
14
32
  - Removed: `OpenapiFirst::Responder` and `OpenapiFirst::RackResponder`
15
33
  - Removed: `OpenapiFirst.app` and `OpenapiFirst.middleware`
16
34
  - Removed: `OpenapiFirst::Coverage`
data/Gemfile CHANGED
@@ -6,6 +6,9 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  group :test, :development do
9
- gem 'pry'
9
+ gem 'bundler'
10
+ gem 'rack-test'
11
+ gem 'rake'
12
+ gem 'rspec'
10
13
  gem 'rubocop'
11
14
  end
data/Gemfile.lock CHANGED
@@ -1,22 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openapi_first (1.0.0.beta3)
4
+ openapi_first (1.0.0.beta5)
5
5
  hanami-router (~> 2.0.0)
6
6
  json_refs (~> 0.1, >= 0.1.7)
7
- json_schemer (~> 0.2.16)
8
- multi_json (~> 1.14)
9
- openapi_parameters (~> 0.2)
7
+ json_schemer (~> 2.0.0)
8
+ multi_json (~> 1.15)
9
+ openapi_parameters (>= 0.3.1, < 2.0)
10
10
  rack (>= 2.2, < 4.0)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
15
  ast (2.4.2)
16
- coderay (1.1.3)
17
16
  diff-lcs (1.5.0)
18
- ecma-re-validator (0.4.0)
19
- regexp_parser (~> 2.2)
20
17
  hana (1.3.7)
21
18
  hanami-router (2.0.2)
22
19
  mustermann (~> 3.0)
@@ -24,77 +21,80 @@ GEM
24
21
  rack (~> 2.0)
25
22
  hansi (0.2.1)
26
23
  json (2.6.3)
27
- json_refs (0.1.7)
24
+ json_refs (0.1.8)
28
25
  hana
29
- json_schemer (0.2.24)
30
- ecma-re-validator (~> 0.3)
26
+ json_schemer (2.0.0)
31
27
  hana (~> 1.3)
32
28
  regexp_parser (~> 2.0)
33
- uri_template (~> 0.7)
34
- method_source (1.0.0)
29
+ simpleidn (~> 0.2)
30
+ language_server-protocol (3.17.0.3)
35
31
  multi_json (1.15.0)
36
32
  mustermann (3.0.0)
37
33
  ruby2_keywords (~> 0.0.1)
38
34
  mustermann-contrib (3.0.0)
39
35
  hansi (~> 0.2.0)
40
36
  mustermann (= 3.0.0)
41
- openapi_parameters (0.2.1)
37
+ openapi_parameters (0.3.1)
42
38
  rack (>= 2.2)
43
39
  zeitwerk (~> 2.6)
44
- parallel (1.22.1)
45
- parser (3.2.1.1)
40
+ parallel (1.23.0)
41
+ parser (3.2.2.4)
46
42
  ast (~> 2.4.1)
47
- pry (0.14.2)
48
- coderay (~> 1.1)
49
- method_source (~> 1.0)
50
- rack (2.2.6.4)
51
- rack-test (1.1.0)
52
- rack (>= 1.0, < 3)
43
+ racc
44
+ racc (1.7.3)
45
+ rack (2.2.8)
46
+ rack-test (2.1.0)
47
+ rack (>= 1.3)
53
48
  rainbow (3.1.1)
54
- rake (13.0.6)
55
- regexp_parser (2.7.0)
56
- rexml (3.2.5)
49
+ rake (13.1.0)
50
+ regexp_parser (2.8.2)
51
+ rexml (3.2.6)
57
52
  rspec (3.12.0)
58
53
  rspec-core (~> 3.12.0)
59
54
  rspec-expectations (~> 3.12.0)
60
55
  rspec-mocks (~> 3.12.0)
61
- rspec-core (3.12.1)
56
+ rspec-core (3.12.2)
62
57
  rspec-support (~> 3.12.0)
63
- rspec-expectations (3.12.2)
58
+ rspec-expectations (3.12.3)
64
59
  diff-lcs (>= 1.2.0, < 2.0)
65
60
  rspec-support (~> 3.12.0)
66
- rspec-mocks (3.12.5)
61
+ rspec-mocks (3.12.6)
67
62
  diff-lcs (>= 1.2.0, < 2.0)
68
63
  rspec-support (~> 3.12.0)
69
- rspec-support (3.12.0)
70
- rubocop (1.48.1)
64
+ rspec-support (3.12.1)
65
+ rubocop (1.57.2)
71
66
  json (~> 2.3)
67
+ language_server-protocol (>= 3.17.0)
72
68
  parallel (~> 1.10)
73
- parser (>= 3.2.0.0)
69
+ parser (>= 3.2.2.4)
74
70
  rainbow (>= 2.2.2, < 4.0)
75
71
  regexp_parser (>= 1.8, < 3.0)
76
72
  rexml (>= 3.2.5, < 4.0)
77
- rubocop-ast (>= 1.26.0, < 2.0)
73
+ rubocop-ast (>= 1.28.1, < 2.0)
78
74
  ruby-progressbar (~> 1.7)
79
75
  unicode-display_width (>= 2.4.0, < 3.0)
80
- rubocop-ast (1.28.0)
76
+ rubocop-ast (1.30.0)
81
77
  parser (>= 3.2.1.0)
82
78
  ruby-progressbar (1.13.0)
83
79
  ruby2_keywords (0.0.5)
84
- unicode-display_width (2.4.2)
85
- uri_template (0.7.0)
86
- zeitwerk (2.6.7)
80
+ simpleidn (0.2.1)
81
+ unf (~> 0.1.4)
82
+ unf (0.1.4)
83
+ unf_ext
84
+ unf_ext (0.0.9)
85
+ unicode-display_width (2.5.0)
86
+ zeitwerk (2.6.12)
87
87
 
88
88
  PLATFORMS
89
89
  arm64-darwin-21
90
+ x86_64-linux
90
91
 
91
92
  DEPENDENCIES
92
- bundler (~> 2)
93
+ bundler
93
94
  openapi_first!
94
- pry
95
- rack-test (~> 1)
96
- rake (~> 13)
97
- rspec (~> 3)
95
+ rack-test
96
+ rake
97
+ rspec
98
98
  rubocop
99
99
 
100
100
  BUNDLED WITH
data/README.md CHANGED
@@ -2,7 +2,7 @@
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.
5
+ OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description. It supports OpenAPI 3.0 and 3.1.
6
6
 
7
7
  It provides these Rack middlewares:
8
8
 
@@ -10,6 +10,8 @@ It provides these Rack middlewares:
10
10
  - [`OpenapiFirst::ResponseValidation`](#response-validation) Validates the response and raises an exception if the response body is invalid.
11
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.
12
12
 
13
+ Using Request and Response validation together ensures that your implementation follows exactly the API description. This enables you to use the API description as a single source of truth for your API, reason about details and use various tooling.
14
+
13
15
  ## Request Validation
14
16
 
15
17
  The `OpenapiFirst::RequestValidation` middleware returns a 400 status code with a body that describes the error if the request is not valid.
@@ -19,16 +21,18 @@ use OpenapiFirst::RequestValidation, spec: 'openapi.yaml'
19
21
  ```
20
22
 
21
23
  It adds these fields to the Rack env:
24
+
22
25
  - `env[OpenapiFirst::PARAMS]` – The parsed parameters (query, path) for the current request (string keyed)
23
26
  - `env[OpenapiFirst::REQUEST_BODY]` – The parsed request body (string keyed)
24
27
  - `env[OpenapiFirst::OPERATION]` (Added via Router) – The Operation object for the current request. This is an instance of `OpenapiFirst::Operation`.
25
28
 
26
29
  ### Options and defaults
27
30
 
28
- | Name | Possible values | Description | Default |
29
- | :------------- | --------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- |
30
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load`
31
- | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` instead of returning 4xx. | `false` (don't raise an exception) |
31
+ | Name | Possible values | Description | Default |
32
+ | :---------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- |
33
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
34
+ | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` instead of returning 4xx. | `false` (don't raise an exception) |
35
+ | `error_response:` | `:default`, `:json_api`, Your implementation of `ErrorResponse` | :default |
32
36
 
33
37
  The error responses conform with [JSON:API](https://jsonapi.org).
34
38
 
@@ -36,7 +40,7 @@ Here's an example response body for a missing query parameter "search":
36
40
 
37
41
  ```json
38
42
  http-status: 400
39
- content-type: "application/vnd.api+json"
43
+ content-type: "application/json"
40
44
 
41
45
  {
42
46
  "errors": [
@@ -72,9 +76,10 @@ This middleware adds the parsed request body to `env[OpenapiFirst::REQUEST_BODY]
72
76
 
73
77
  The middleware will return a status `415` if the requests content type does not match or `400` if the request body is invalid.
74
78
 
75
- ### Header, Cookie, Path parameter validation
79
+ ### Header, Cookie, Query and Path parameter validation
76
80
 
77
- tbd.
81
+ The `RequestValidation` middleware validates the request headers, cookies and path parameters as defined in you API description. It returns a `400` status code if the request is invalid. It adds the parsed merged _path_ and _query_ parameters to `env['openapi.params']`.
82
+ Separate parsed parameters are made available by location at `env['openapi.path_params']`, `env['openapi.query']`, `env['openapi.headers']`, `env['openapi.cookies']` as well if you need to access them separately.
78
83
 
79
84
  ### readOnly / writeOnly properties
80
85
 
@@ -92,9 +97,9 @@ use OpenapiFirst::ResponseValidation, spec: 'openapi.yaml' if ENV['RACK_ENV'] ==
92
97
 
93
98
  ### Options
94
99
 
95
- | Name | Possible values | Description | Default |
96
- | :------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
97
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load`
100
+ | Name | Possible values | Description | Default |
101
+ | :------ | --------------- | ---------------------------------------------------------------- | ------- |
102
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
98
103
 
99
104
  ## OpenapiFirst::Router
100
105
 
@@ -104,16 +109,27 @@ This middleware is used automatically, but you can add it to the top of your mid
104
109
  use OpenapiFirst::Router, spec: './openapi/openapi.yaml'
105
110
  ```
106
111
 
107
- This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation object that responds to `#operation_id`, `#path` (and `#[string]` to access raw fields).
112
+ This middleware adds `env['openapi.operation']` which holds an instance of `OpenapiFirst::Operation` that responds to `#operation_id`, `#path` (and `#[]` to access raw fields).
108
113
 
109
114
  ### Options and defaults
110
115
 
111
116
  | Name | Possible values | Description | Default |
112
117
  | :------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
113
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` | |
118
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` | |
114
119
  | `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) |
115
120
  | `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) |
116
121
 
122
+ ## Global configuration
123
+
124
+ You can configure default options gobally via `OpenapiFirst::Config`:
125
+
126
+ ```ruby
127
+ OpenapiFirst::Config.default_options = {
128
+ error_response: :json_api,
129
+ request_validation_raise_error: true
130
+ }
131
+ ```
132
+
117
133
  ## Alternatives
118
134
 
119
135
  This gem is inspired by [committee](https://github.com/interagent/committee) (Ruby) and [connexion](https://github.com/zalando/connexion) (Python).
@@ -160,9 +176,9 @@ run OpenapiFirst.app(spec, namespace: Pets)
160
176
 
161
177
  Run `bin/setup` to install dependencies.
162
178
 
163
- Run `bundle exec rspec` to run the tests.
179
+ See `bundle exec rake` to run the linter and the tests.
164
180
 
165
- See `bundle exec rake -T` for rubygems related tasks.
181
+ Run `bundle exec rspec` to run the tests only.
166
182
 
167
183
  ## Benchmarks
168
184
 
@@ -1,32 +1,42 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- openapi_first (1.0.0.beta3)
4
+ openapi_first (1.0.0.beta5)
5
5
  hanami-router (~> 2.0.0)
6
6
  json_refs (~> 0.1, >= 0.1.7)
7
- json_schemer (~> 0.2.16)
8
- multi_json (~> 1.14)
9
- openapi_parameters (~> 0.2)
7
+ json_schemer (~> 2.0.0)
8
+ multi_json (~> 1.15)
9
+ openapi_parameters (>= 0.3.1, < 2.0)
10
10
  rack (>= 2.2, < 4.0)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
- activesupport (7.0.4.3)
15
+ activesupport (7.1.2)
16
+ base64
17
+ bigdecimal
16
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ connection_pool (>= 2.2.5)
20
+ drb
17
21
  i18n (>= 1.6, < 2)
18
22
  minitest (>= 5.1)
23
+ mutex_m
19
24
  tzinfo (~> 2.0)
25
+ base64 (0.2.0)
20
26
  benchmark-ips (2.12.0)
21
27
  benchmark-memory (0.2.0)
22
28
  memory_profiler (~> 1)
29
+ bigdecimal (3.1.4)
23
30
  builder (3.2.4)
24
31
  committee (5.0.0)
25
32
  json_schema (~> 0.14, >= 0.14.3)
26
33
  openapi_parser (~> 1.0)
27
34
  rack (>= 1.5)
28
35
  concurrent-ruby (1.2.2)
29
- dry-core (1.0.0)
36
+ connection_pool (2.4.1)
37
+ drb (2.2.0)
38
+ ruby2_keywords
39
+ dry-core (1.0.1)
30
40
  concurrent-ruby (~> 1.0)
31
41
  zeitwerk (~> 2.6)
32
42
  dry-inflector (1.0.0)
@@ -40,10 +50,8 @@ GEM
40
50
  dry-inflector (~> 1.0)
41
51
  dry-logic (~> 1.4)
42
52
  zeitwerk (~> 2.6)
43
- ecma-re-validator (0.4.0)
44
- regexp_parser (~> 2.2)
45
- grape (1.7.0)
46
- activesupport
53
+ grape (2.0.0)
54
+ activesupport (>= 5)
47
55
  builder
48
56
  dry-types (>= 1.1)
49
57
  mustermann-grape (~> 1.0.0)
@@ -57,18 +65,17 @@ GEM
57
65
  mustermann-contrib (~> 3.0)
58
66
  rack (~> 2.0)
59
67
  hansi (0.2.1)
60
- i18n (1.12.0)
68
+ i18n (1.14.1)
61
69
  concurrent-ruby (~> 1.0)
62
- json_refs (0.1.7)
70
+ json_refs (0.1.8)
63
71
  hana
64
72
  json_schema (0.21.0)
65
- json_schemer (0.2.24)
66
- ecma-re-validator (~> 0.3)
73
+ json_schemer (2.0.0)
67
74
  hana (~> 1.3)
68
75
  regexp_parser (~> 2.0)
69
- uri_template (~> 0.7)
76
+ simpleidn (~> 0.2)
70
77
  memory_profiler (1.0.1)
71
- minitest (5.18.0)
78
+ minitest (5.20.0)
72
79
  multi_json (1.15.0)
73
80
  mustermann (3.0.0)
74
81
  ruby2_keywords (~> 0.0.1)
@@ -77,36 +84,41 @@ GEM
77
84
  mustermann (= 3.0.0)
78
85
  mustermann-grape (1.0.2)
79
86
  mustermann (>= 1.0.0)
87
+ mutex_m (0.2.0)
80
88
  nio4r (2.5.9)
81
- openapi_parameters (0.2.1)
89
+ openapi_parameters (0.3.1)
82
90
  rack (>= 2.2)
83
91
  zeitwerk (~> 2.6)
84
92
  openapi_parser (1.0.0)
85
- puma (6.2.2)
93
+ puma (6.4.0)
86
94
  nio4r (~> 2.0)
87
- rack (2.2.6.4)
95
+ rack (2.2.8)
88
96
  rack-accept (0.4.5)
89
97
  rack (>= 0.4)
90
- rack-protection (3.0.6)
91
- rack
92
- regexp_parser (2.8.0)
93
- roda (3.67.0)
98
+ rack-protection (3.1.0)
99
+ rack (~> 2.2, >= 2.2.4)
100
+ regexp_parser (2.8.2)
101
+ roda (3.73.0)
94
102
  rack
95
103
  ruby2_keywords (0.0.5)
96
104
  seg (1.2.0)
97
- sinatra (3.0.6)
105
+ simpleidn (0.2.1)
106
+ unf (~> 0.1.4)
107
+ sinatra (3.1.0)
98
108
  mustermann (~> 3.0)
99
109
  rack (~> 2.2, >= 2.2.4)
100
- rack-protection (= 3.0.6)
110
+ rack-protection (= 3.1.0)
101
111
  tilt (~> 2.0)
102
112
  syro (3.2.1)
103
113
  rack (>= 1.6.0)
104
114
  seg
105
- tilt (2.1.0)
115
+ tilt (2.3.0)
106
116
  tzinfo (2.0.6)
107
117
  concurrent-ruby (~> 1.0)
108
- uri_template (0.7.0)
109
- zeitwerk (2.6.7)
118
+ unf (0.1.4)
119
+ unf_ext
120
+ unf_ext (0.0.9)
121
+ zeitwerk (2.6.12)
110
122
 
111
123
  PLATFORMS
112
124
  arm64-darwin-21
@@ -24,9 +24,9 @@ app = Rack::Builder.new do
24
24
 
25
25
  not_found = ->(_env) { [404, {}, []] }
26
26
 
27
- run lambda do |env|
27
+ run(lambda do |env|
28
28
  handlers.fetch(env[OpenapiFirst::OPERATION]&.operation_id, not_found).call(env)
29
- end
29
+ end)
30
30
  end
31
31
 
32
32
  run app
@@ -4,29 +4,16 @@ require 'multi_json'
4
4
 
5
5
  module OpenapiFirst
6
6
  class BodyParserMiddleware
7
- def initialize(app, options = {})
7
+ def initialize(app)
8
8
  @app = app
9
- @raise = options.fetch(:raise_error, false)
10
9
  end
11
10
 
12
- RACK_INPUT = 'rack.input'
13
11
  ROUTER_PARSED_BODY = 'router.parsed_body'
12
+ private_constant :ROUTER_PARSED_BODY
14
13
 
15
14
  def call(env)
16
15
  env[ROUTER_PARSED_BODY] = parse_body(env)
17
16
  @app.call(env)
18
- rescue BodyParsingError => e
19
- raise if @raise
20
-
21
- err = { title: "Failed to parse body as #{env['CONTENT_TYPE']}", status: '400' }
22
- err[:detail] = e.cause unless ENV['RACK_ENV'] == 'production'
23
- errors = [err]
24
-
25
- Rack::Response.new(
26
- MultiJson.dump(errors: errors),
27
- 400,
28
- Rack::CONTENT_TYPE => 'application/vnd.api+json'
29
- ).finish
30
17
  end
31
18
 
32
19
  private
@@ -40,8 +27,8 @@ module OpenapiFirst
40
27
  return request.POST if request.form_data?
41
28
 
42
29
  body
43
- rescue MultiJson::ParseError => e
44
- raise BodyParsingError, e
30
+ rescue MultiJson::ParseError
31
+ raise BodyParsingError, 'Failed to parse body as application/json'
45
32
  end
46
33
 
47
34
  def read_body(request)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ class Config
5
+ def initialize(error_response: :default, request_validation_raise_error: false)
6
+ @error_response = Plugins.find_error_response(error_response)
7
+ @request_validation_raise_error = request_validation_raise_error
8
+ end
9
+
10
+ attr_reader :error_response, :request_validation_raise_error
11
+
12
+ def self.default_options
13
+ @default_options ||= new
14
+ end
15
+
16
+ def self.default_options=(options)
17
+ @default_options = new(**options)
18
+ end
19
+ end
20
+ end
@@ -3,6 +3,7 @@
3
3
  require_relative 'operation'
4
4
 
5
5
  module OpenapiFirst
6
+ # Represents an OpenAPI API Description document
6
7
  class Definition
7
8
  attr_reader :filepath, :operations
8
9
 
@@ -11,9 +12,15 @@ module OpenapiFirst
11
12
  methods = %w[get head post put patch delete trace options]
12
13
  @operations = resolved['paths'].flat_map do |path, path_item|
13
14
  path_item.slice(*methods).map do |request_method, _operation_object|
14
- Operation.new(path, request_method, path_item)
15
+ Operation.new(path, request_method, path_item, openapi_version: detect_version(resolved))
15
16
  end
16
17
  end
17
18
  end
19
+
20
+ private
21
+
22
+ def detect_version(resolved)
23
+ (resolved['openapi'] || resolved['swagger'])[0..2]
24
+ end
18
25
  end
19
26
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ # This is the base class for error responses
5
+ class ErrorResponse
6
+ ## @param request [Hash] The Rack request env
7
+ ## @param request_validation_error [OpenapiFirst::RequestValidationError]
8
+ def initialize(env, request_validation_error)
9
+ @env = env
10
+ @request_validation_error = request_validation_error
11
+ end
12
+
13
+ extend Forwardable
14
+
15
+ attr_reader :env, :request_validation_error
16
+
17
+ def_delegators :@request_validation_error, :status, :location, :schema_validation
18
+
19
+ def validation_output
20
+ schema_validation&.output
21
+ end
22
+
23
+ def schema
24
+ schema_validation&.schema
25
+ end
26
+
27
+ def data
28
+ schema_validation&.data
29
+ end
30
+
31
+ def message
32
+ request_validation_error.message
33
+ end
34
+
35
+ def render
36
+ Rack::Response.new(body, status, Rack::CONTENT_TYPE => content_type).finish
37
+ end
38
+
39
+ def content_type = 'application/json'
40
+
41
+ def body
42
+ raise NotImplementedError
43
+ end
44
+ end
45
+ end