openapi_first 1.0.0.beta3 → 1.0.0.beta5

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