openapi_first 0.12.0 → 0.12.5
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 +4 -4
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +17 -17
- data/README.md +18 -1
- data/benchmarks/Gemfile.lock +12 -12
- data/examples/app.rb +2 -1
- data/lib/openapi_first.rb +29 -4
- data/lib/openapi_first/app.rb +11 -4
- data/lib/openapi_first/operation.rb +16 -1
- data/lib/openapi_first/request_validation.rb +2 -1
- data/lib/openapi_first/response_validation.rb +6 -2
- data/lib/openapi_first/router.rb +6 -4
- data/lib/openapi_first/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e8692df035f2c27738cc74a8265ad45f6235397c0ce35059fdeef29ef54402ba
|
|
4
|
+
data.tar.gz: 156a0c22674e9eed4b2a7ffdfff1cde726b721bf63e8cede6c0d006442c72890
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f4bedb9b730bb1c27a29d04fe7b915f2e61b0ac6305d6faccb52fd7baa962356704ce0ec85c192f36b9bb5ba9323d29cefa014d287c564fc48dcdaa8bd953a1
|
|
7
|
+
data.tar.gz: 9341ba6927183ad541b0b5d3dbc4096112a74204ce14abd1b2c72bfa339c757853f93041f80df85aa51d83377380d9ba034ce260885a5ddbbc64cb769e177d16
|
data/.rubocop.yml
CHANGED
|
@@ -14,6 +14,8 @@ Layout/SpaceAroundMethodCallOperator:
|
|
|
14
14
|
Enabled: true
|
|
15
15
|
Lint/DeprecatedOpenSSLConstant:
|
|
16
16
|
Enabled: true
|
|
17
|
+
Lint/DuplicateElsifCondition:
|
|
18
|
+
Enabled: true
|
|
17
19
|
Lint/RaiseException:
|
|
18
20
|
Enabled: true
|
|
19
21
|
Lint/MixedRegexpCaptureTypes:
|
|
@@ -28,7 +30,25 @@ Lint/StructNewOverride:
|
|
|
28
30
|
Enabled: true
|
|
29
31
|
Style/HashEachMethods:
|
|
30
32
|
Enabled: false
|
|
33
|
+
Style/AccessorGrouping:
|
|
34
|
+
Enabled: true
|
|
35
|
+
Style/ArrayCoercion:
|
|
36
|
+
Enabled: true
|
|
37
|
+
Style/BisectedAttrAccessor:
|
|
38
|
+
Enabled: true
|
|
39
|
+
Style/CaseLikeIf:
|
|
40
|
+
Enabled: true
|
|
41
|
+
Style/HashAsLastArrayItem:
|
|
42
|
+
Enabled: true
|
|
43
|
+
Style/HashLikeCase:
|
|
44
|
+
Enabled: true
|
|
31
45
|
Style/HashTransformKeys:
|
|
32
46
|
Enabled: true
|
|
33
47
|
Style/HashTransformValues:
|
|
34
48
|
Enabled: true
|
|
49
|
+
Style/RedundantAssignment:
|
|
50
|
+
Enabled: true
|
|
51
|
+
Style/RedundantFetchBlock:
|
|
52
|
+
Enabled: true
|
|
53
|
+
Style/RedundantFileExtensionInRequire:
|
|
54
|
+
Enabled: true
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.5
|
|
4
|
+
- Add `not_found: :continue` option to Router to make it do nothing if request is unknown
|
|
5
|
+
|
|
6
|
+
## 0.12.4
|
|
7
|
+
- content-type is found while ignoring additional content-type parameters (`application/json` is found when request/response content-type is `application/json; charset=UTF8`)
|
|
8
|
+
- Support wildcard mime-types when finding the content-type
|
|
9
|
+
|
|
10
|
+
## 0.12.3
|
|
11
|
+
- Add `response_validation:`, `router_raise_error` options to standalone mode.
|
|
12
|
+
|
|
13
|
+
## 0.12.2
|
|
14
|
+
- Allow response to have no media type object specified
|
|
15
|
+
|
|
16
|
+
## 0.12.1
|
|
17
|
+
- Fix response when handler returns 404 or 405
|
|
18
|
+
- Don't validate the response content if status is 205 (no content)
|
|
19
|
+
|
|
3
20
|
## 0.12.0
|
|
4
21
|
- Change `ResponseValidator` to raise an exception if it found a problem
|
|
5
22
|
- Params have symbolized keys now
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
openapi_first (0.12.
|
|
4
|
+
openapi_first (0.12.5)
|
|
5
5
|
deep_merge (>= 1.2.1)
|
|
6
6
|
hanami-router (~> 2.0.alpha3)
|
|
7
7
|
hanami-utils (~> 2.0.alpha1)
|
|
@@ -13,7 +13,7 @@ PATH
|
|
|
13
13
|
GEM
|
|
14
14
|
remote: https://rubygems.org/
|
|
15
15
|
specs:
|
|
16
|
-
activesupport (6.0.3.
|
|
16
|
+
activesupport (6.0.3.2)
|
|
17
17
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
18
18
|
i18n (>= 0.7, < 2)
|
|
19
19
|
minitest (~> 5.1)
|
|
@@ -24,9 +24,9 @@ GEM
|
|
|
24
24
|
ast (2.4.1)
|
|
25
25
|
builder (3.2.4)
|
|
26
26
|
coderay (1.1.3)
|
|
27
|
-
concurrent-ruby (1.1.
|
|
27
|
+
concurrent-ruby (1.1.7)
|
|
28
28
|
deep_merge (1.2.1)
|
|
29
|
-
diff-lcs (1.
|
|
29
|
+
diff-lcs (1.4.4)
|
|
30
30
|
ecma-re-validator (0.2.1)
|
|
31
31
|
regexp_parser (~> 1.2)
|
|
32
32
|
hana (1.3.6)
|
|
@@ -39,9 +39,9 @@ GEM
|
|
|
39
39
|
transproc (~> 1.0)
|
|
40
40
|
hansi (0.2.0)
|
|
41
41
|
hash-deep-merge (0.1.1)
|
|
42
|
-
i18n (1.8.
|
|
42
|
+
i18n (1.8.5)
|
|
43
43
|
concurrent-ruby (~> 1.0)
|
|
44
|
-
json_schemer (0.2.
|
|
44
|
+
json_schemer (0.2.13)
|
|
45
45
|
ecma-re-validator (~> 0.2)
|
|
46
46
|
hana (~> 1.3)
|
|
47
47
|
regexp_parser (~> 1.5)
|
|
@@ -49,13 +49,13 @@ GEM
|
|
|
49
49
|
method_source (1.0.0)
|
|
50
50
|
mini_portile2 (2.4.0)
|
|
51
51
|
minitest (5.14.1)
|
|
52
|
-
multi_json (1.
|
|
52
|
+
multi_json (1.15.0)
|
|
53
53
|
mustermann (1.1.1)
|
|
54
54
|
ruby2_keywords (~> 0.0.1)
|
|
55
55
|
mustermann-contrib (1.1.1)
|
|
56
56
|
hansi (~> 0.2.0)
|
|
57
57
|
mustermann (= 1.1.1)
|
|
58
|
-
nokogiri (1.10.
|
|
58
|
+
nokogiri (1.10.10)
|
|
59
59
|
mini_portile2 (~> 2.4.0)
|
|
60
60
|
oas_parser (0.25.1)
|
|
61
61
|
activesupport (>= 4.0.0)
|
|
@@ -65,14 +65,14 @@ GEM
|
|
|
65
65
|
hash-deep-merge
|
|
66
66
|
mustermann-contrib (~> 1.1.1)
|
|
67
67
|
nokogiri
|
|
68
|
-
parallel (1.19.
|
|
69
|
-
parser (2.7.1.
|
|
70
|
-
ast (~> 2.4.
|
|
68
|
+
parallel (1.19.2)
|
|
69
|
+
parser (2.7.1.4)
|
|
70
|
+
ast (~> 2.4.1)
|
|
71
71
|
pry (0.13.1)
|
|
72
72
|
coderay (~> 1.1)
|
|
73
73
|
method_source (~> 1.0)
|
|
74
74
|
public_suffix (4.0.5)
|
|
75
|
-
rack (2.2.
|
|
75
|
+
rack (2.2.3)
|
|
76
76
|
rack-test (1.1.0)
|
|
77
77
|
rack (>= 1.0, < 3)
|
|
78
78
|
rainbow (3.0.0)
|
|
@@ -92,16 +92,16 @@ GEM
|
|
|
92
92
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
93
93
|
rspec-support (~> 3.9.0)
|
|
94
94
|
rspec-support (3.9.3)
|
|
95
|
-
rubocop (0.
|
|
95
|
+
rubocop (0.88.0)
|
|
96
96
|
parallel (~> 1.10)
|
|
97
|
-
parser (>= 2.7.
|
|
97
|
+
parser (>= 2.7.1.1)
|
|
98
98
|
rainbow (>= 2.2.2, < 4.0)
|
|
99
99
|
regexp_parser (>= 1.7)
|
|
100
100
|
rexml
|
|
101
|
-
rubocop-ast (>= 0.0.
|
|
101
|
+
rubocop-ast (>= 0.1.0, < 1.0)
|
|
102
102
|
ruby-progressbar (~> 1.7)
|
|
103
103
|
unicode-display_width (>= 1.4.0, < 2.0)
|
|
104
|
-
rubocop-ast (0.0
|
|
104
|
+
rubocop-ast (0.2.0)
|
|
105
105
|
parser (>= 2.7.0.1)
|
|
106
106
|
ruby-progressbar (1.10.1)
|
|
107
107
|
ruby2_keywords (0.0.2)
|
|
@@ -111,7 +111,7 @@ GEM
|
|
|
111
111
|
thread_safe (~> 0.1)
|
|
112
112
|
unicode-display_width (1.7.0)
|
|
113
113
|
uri_template (0.7.0)
|
|
114
|
-
zeitwerk (2.
|
|
114
|
+
zeitwerk (2.4.0)
|
|
115
115
|
|
|
116
116
|
PLATFORMS
|
|
117
117
|
ruby
|
data/README.md
CHANGED
|
@@ -37,6 +37,7 @@ Options and their defaults:
|
|
|
37
37
|
|:---|---|---|---|
|
|
38
38
|
|`spec:`| | The spec loaded via `OpenapiFirst.load` ||
|
|
39
39
|
| `raise_error:` |`false`, `true` | If set to true the middleware raises `OpenapiFirst::NotFoundError` when a path or method was not found in the API description. This is useful during testing to spot an incomplete API description. | `false` (don't raise an exception)
|
|
40
|
+
| `not_found:` | `:continue`, `:halt`| If set to `:continue` the middleware will not return 404 (405, 415), but just pass handling the request to the next middleware or application in the Rack stack. If combined with `raise_error: true` `raise_error` gets preference and an exception is raised. | `:halt` (return 4xx response)
|
|
40
41
|
|
|
41
42
|
## OpenapiFirst::RequestValidation
|
|
42
43
|
|
|
@@ -150,7 +151,12 @@ end
|
|
|
150
151
|
|
|
151
152
|
# In config.ru:
|
|
152
153
|
require 'openapi_first'
|
|
153
|
-
run OpenapiFirst.app(
|
|
154
|
+
run OpenapiFirst.app(
|
|
155
|
+
'./openapi/openapi.yaml',
|
|
156
|
+
namespace: Pets,
|
|
157
|
+
response_validation: ENV['RACK_ENV'] == 'test',
|
|
158
|
+
router_raise_error: ENV['RACK_ENV'] == 'test'
|
|
159
|
+
)
|
|
154
160
|
```
|
|
155
161
|
|
|
156
162
|
The above will use the mentioned Rack middlewares to:
|
|
@@ -159,6 +165,17 @@ The above will use the mentioned Rack middlewares to:
|
|
|
159
165
|
- Map the request to a method call `Pets.find_pet` based on the `operationId` in the API description
|
|
160
166
|
- Set the response content type according to your spec (here with the default status code `200`)
|
|
161
167
|
|
|
168
|
+
### Options and their defaults:
|
|
169
|
+
|
|
170
|
+
| Name | Possible values | Description | Default
|
|
171
|
+
|:---|---|---|---|
|
|
172
|
+
| `spec_path` || A filepath to an OpenAPI definition file. |
|
|
173
|
+
| `namespace:` || A class or module where to find the handler methods.|
|
|
174
|
+
| `response_validation:` | `true`, `false` | If set to true it raises an exception if the response is invalid. This is useful during testing. | `false`
|
|
175
|
+
| `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`
|
|
176
|
+
| `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`
|
|
177
|
+
|
|
178
|
+
|
|
162
179
|
Handler functions (`find_pet`) are called with two arguments:
|
|
163
180
|
|
|
164
181
|
- `params` - Holds the parsed request body, filtered query params and path parameters
|
data/benchmarks/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
openapi_first (0.12.
|
|
4
|
+
openapi_first (0.12.5)
|
|
5
5
|
deep_merge (>= 1.2.1)
|
|
6
6
|
hanami-router (~> 2.0.alpha3)
|
|
7
7
|
hanami-utils (~> 2.0.alpha1)
|
|
@@ -13,7 +13,7 @@ PATH
|
|
|
13
13
|
GEM
|
|
14
14
|
remote: https://rubygems.org/
|
|
15
15
|
specs:
|
|
16
|
-
activesupport (6.0.3.
|
|
16
|
+
activesupport (6.0.3.2)
|
|
17
17
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
18
18
|
i18n (>= 0.7, < 2)
|
|
19
19
|
minitest (~> 5.1)
|
|
@@ -25,13 +25,13 @@ GEM
|
|
|
25
25
|
benchmark-memory (0.1.2)
|
|
26
26
|
memory_profiler (~> 0.9)
|
|
27
27
|
builder (3.2.4)
|
|
28
|
-
committee (4.
|
|
28
|
+
committee (4.1.0)
|
|
29
29
|
json_schema (~> 0.14, >= 0.14.3)
|
|
30
30
|
openapi_parser (>= 0.11.1)
|
|
31
31
|
rack (>= 1.5)
|
|
32
32
|
concurrent-ruby (1.1.6)
|
|
33
33
|
deep_merge (1.2.1)
|
|
34
|
-
dry-configurable (0.11.
|
|
34
|
+
dry-configurable (0.11.6)
|
|
35
35
|
concurrent-ruby (~> 1.0)
|
|
36
36
|
dry-core (~> 0.4, >= 0.4.7)
|
|
37
37
|
dry-equalizer (~> 0.2)
|
|
@@ -55,7 +55,7 @@ GEM
|
|
|
55
55
|
dry-logic (~> 1.0, >= 1.0.2)
|
|
56
56
|
ecma-re-validator (0.2.1)
|
|
57
57
|
regexp_parser (~> 1.2)
|
|
58
|
-
grape (1.
|
|
58
|
+
grape (1.4.0)
|
|
59
59
|
activesupport
|
|
60
60
|
builder
|
|
61
61
|
dry-types (>= 1.1)
|
|
@@ -72,10 +72,10 @@ GEM
|
|
|
72
72
|
transproc (~> 1.0)
|
|
73
73
|
hansi (0.2.0)
|
|
74
74
|
hash-deep-merge (0.1.1)
|
|
75
|
-
i18n (1.8.
|
|
75
|
+
i18n (1.8.4)
|
|
76
76
|
concurrent-ruby (~> 1.0)
|
|
77
|
-
json_schema (0.20.
|
|
78
|
-
json_schemer (0.2.
|
|
77
|
+
json_schema (0.20.9)
|
|
78
|
+
json_schemer (0.2.13)
|
|
79
79
|
ecma-re-validator (~> 0.2)
|
|
80
80
|
hana (~> 1.3)
|
|
81
81
|
regexp_parser (~> 1.5)
|
|
@@ -83,7 +83,7 @@ GEM
|
|
|
83
83
|
memory_profiler (0.9.14)
|
|
84
84
|
mini_portile2 (2.4.0)
|
|
85
85
|
minitest (5.14.1)
|
|
86
|
-
multi_json (1.
|
|
86
|
+
multi_json (1.15.0)
|
|
87
87
|
mustermann (1.1.1)
|
|
88
88
|
ruby2_keywords (~> 0.0.1)
|
|
89
89
|
mustermann-contrib (1.1.1)
|
|
@@ -91,7 +91,7 @@ GEM
|
|
|
91
91
|
mustermann (= 1.1.1)
|
|
92
92
|
mustermann-grape (1.0.1)
|
|
93
93
|
mustermann (>= 1.0.0)
|
|
94
|
-
nokogiri (1.10.
|
|
94
|
+
nokogiri (1.10.10)
|
|
95
95
|
mini_portile2 (~> 2.4.0)
|
|
96
96
|
oas_parser (0.25.1)
|
|
97
97
|
activesupport (>= 4.0.0)
|
|
@@ -103,7 +103,7 @@ GEM
|
|
|
103
103
|
nokogiri
|
|
104
104
|
openapi_parser (0.11.2)
|
|
105
105
|
public_suffix (4.0.5)
|
|
106
|
-
rack (2.2.
|
|
106
|
+
rack (2.2.3)
|
|
107
107
|
rack-accept (0.4.5)
|
|
108
108
|
rack (>= 0.4)
|
|
109
109
|
rack-protection (2.0.8.1)
|
|
@@ -125,7 +125,7 @@ GEM
|
|
|
125
125
|
tzinfo (1.2.7)
|
|
126
126
|
thread_safe (~> 0.1)
|
|
127
127
|
uri_template (0.7.0)
|
|
128
|
-
zeitwerk (2.
|
|
128
|
+
zeitwerk (2.4.0)
|
|
129
129
|
|
|
130
130
|
PLATFORMS
|
|
131
131
|
ruby
|
data/examples/app.rb
CHANGED
|
@@ -17,5 +17,6 @@ oas_path = File.absolute_path('./openapi.yaml', __dir__)
|
|
|
17
17
|
App = OpenapiFirst.app(
|
|
18
18
|
oas_path,
|
|
19
19
|
namespace: Web,
|
|
20
|
-
|
|
20
|
+
router_raise_error: OpenapiFirst.env == 'test',
|
|
21
|
+
response_validation: OpenapiFirst.env == 'test'
|
|
21
22
|
)
|
data/lib/openapi_first.rb
CHANGED
|
@@ -31,14 +31,39 @@ module OpenapiFirst
|
|
|
31
31
|
Definition.new(parsed)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def self.app(
|
|
34
|
+
def self.app(
|
|
35
|
+
spec,
|
|
36
|
+
namespace:,
|
|
37
|
+
router_raise_error: false,
|
|
38
|
+
request_validation_raise_error: false,
|
|
39
|
+
response_validation: false
|
|
40
|
+
)
|
|
35
41
|
spec = OpenapiFirst.load(spec) if spec.is_a?(String)
|
|
36
|
-
App.new(
|
|
42
|
+
App.new(
|
|
43
|
+
nil,
|
|
44
|
+
spec,
|
|
45
|
+
namespace: namespace,
|
|
46
|
+
router_raise_error: router_raise_error,
|
|
47
|
+
request_validation_raise_error: request_validation_raise_error,
|
|
48
|
+
response_validation: response_validation
|
|
49
|
+
)
|
|
37
50
|
end
|
|
38
51
|
|
|
39
|
-
def self.middleware(
|
|
52
|
+
def self.middleware(
|
|
53
|
+
spec,
|
|
54
|
+
namespace:,
|
|
55
|
+
router_raise_error: false,
|
|
56
|
+
request_validation_raise_error: false,
|
|
57
|
+
response_validation: false
|
|
58
|
+
)
|
|
40
59
|
spec = OpenapiFirst.load(spec) if spec.is_a?(String)
|
|
41
|
-
AppWithOptions.new(
|
|
60
|
+
AppWithOptions.new(
|
|
61
|
+
spec,
|
|
62
|
+
namespace: namespace,
|
|
63
|
+
router_raise_error: router_raise_error,
|
|
64
|
+
request_validation_raise_error: request_validation_raise_error,
|
|
65
|
+
response_validation: response_validation
|
|
66
|
+
)
|
|
42
67
|
end
|
|
43
68
|
|
|
44
69
|
class AppWithOptions
|
data/lib/openapi_first/app.rb
CHANGED
|
@@ -5,12 +5,19 @@ require 'logger'
|
|
|
5
5
|
|
|
6
6
|
module OpenapiFirst
|
|
7
7
|
class App
|
|
8
|
-
def initialize(
|
|
8
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
9
|
+
parent_app,
|
|
10
|
+
spec,
|
|
11
|
+
namespace:,
|
|
12
|
+
router_raise_error: false,
|
|
13
|
+
request_validation_raise_error: false,
|
|
14
|
+
response_validation: false
|
|
15
|
+
)
|
|
9
16
|
@stack = Rack::Builder.app do
|
|
10
17
|
freeze_app
|
|
11
|
-
use OpenapiFirst::Router, spec: spec, raise_error:
|
|
12
|
-
use OpenapiFirst::RequestValidation, raise_error:
|
|
13
|
-
use OpenapiFirst::ResponseValidation if
|
|
18
|
+
use OpenapiFirst::Router, spec: spec, raise_error: router_raise_error, parent_app: parent_app
|
|
19
|
+
use OpenapiFirst::RequestValidation, raise_error: request_validation_raise_error
|
|
20
|
+
use OpenapiFirst::ResponseValidation if response_validation
|
|
14
21
|
run OpenapiFirst::Responder.new(
|
|
15
22
|
spec: spec,
|
|
16
23
|
namespace: namespace
|
|
@@ -39,7 +39,9 @@ module OpenapiFirst
|
|
|
39
39
|
content = response_for(status)['content']
|
|
40
40
|
return if content.nil? || content.empty?
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
raise ResponseInvalid, "Response has no content-type for '#{name}'" unless content_type
|
|
43
|
+
|
|
44
|
+
media_type = find_content_for_content_type(content, content_type)
|
|
43
45
|
unless media_type
|
|
44
46
|
message = "Response content type not found '#{content_type}' for '#{name}'"
|
|
45
47
|
raise ResponseContentTypeNotFoundError, message
|
|
@@ -47,6 +49,12 @@ module OpenapiFirst
|
|
|
47
49
|
media_type['schema']
|
|
48
50
|
end
|
|
49
51
|
|
|
52
|
+
def request_body_schema_for(request_content_type)
|
|
53
|
+
content = @operation.request_body.content
|
|
54
|
+
media_type = find_content_for_content_type(content, request_content_type)
|
|
55
|
+
media_type&.fetch('schema', nil)
|
|
56
|
+
end
|
|
57
|
+
|
|
50
58
|
def response_for(status)
|
|
51
59
|
@operation.response_by_code(status.to_s, use_default: true).raw
|
|
52
60
|
rescue OasParser::ResponseCodeNotFound
|
|
@@ -60,6 +68,13 @@ module OpenapiFirst
|
|
|
60
68
|
|
|
61
69
|
private
|
|
62
70
|
|
|
71
|
+
def find_content_for_content_type(content, request_content_type)
|
|
72
|
+
content.fetch(request_content_type) do |_|
|
|
73
|
+
type = request_content_type.split(';')[0]
|
|
74
|
+
content[type] || content["#{type.split('/')[0]}/*"] || content['*/*']
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
63
78
|
def build_parameters_json_schema
|
|
64
79
|
return unless @operation.parameters&.any?
|
|
65
80
|
|
|
@@ -98,7 +98,8 @@ module OpenapiFirst
|
|
|
98
98
|
def request_body_schema(content_type, operation)
|
|
99
99
|
return unless operation
|
|
100
100
|
|
|
101
|
-
schema = operation.
|
|
101
|
+
schema = operation.request_body_schema_for(content_type)
|
|
102
|
+
|
|
102
103
|
JSONSchemer.schema(schema) if schema
|
|
103
104
|
end
|
|
104
105
|
|
|
@@ -24,15 +24,19 @@ module OpenapiFirst
|
|
|
24
24
|
|
|
25
25
|
def validate(response, operation)
|
|
26
26
|
status, headers, body = response.to_a
|
|
27
|
-
|
|
28
|
-
raise ResponseInvalid, "Response has no content-type for '#{operation.name}'" unless content_type
|
|
27
|
+
return validate_status_only(operation, status) if status == 204
|
|
29
28
|
|
|
29
|
+
content_type = headers[Rack::CONTENT_TYPE]
|
|
30
30
|
response_schema = operation.response_schema_for(status, content_type)
|
|
31
31
|
validate_response_body(response_schema, body) if response_schema
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
|
+
def validate_status_only(operation, status)
|
|
37
|
+
operation.response_for(status)
|
|
38
|
+
end
|
|
39
|
+
|
|
36
40
|
def validate_response_body(schema, response)
|
|
37
41
|
full_body = +''
|
|
38
42
|
response.each { |chunk| full_body << chunk }
|
data/lib/openapi_first/router.rb
CHANGED
|
@@ -10,11 +10,13 @@ module OpenapiFirst
|
|
|
10
10
|
app,
|
|
11
11
|
spec:,
|
|
12
12
|
raise_error: false,
|
|
13
|
+
not_found: :halt,
|
|
13
14
|
parent_app: nil
|
|
14
15
|
)
|
|
15
16
|
@app = app
|
|
16
17
|
@parent_app = parent_app
|
|
17
18
|
@raise = raise_error
|
|
19
|
+
@not_found = not_found
|
|
18
20
|
@filepath = spec.filepath
|
|
19
21
|
@router = build_router(spec.operations)
|
|
20
22
|
end
|
|
@@ -22,16 +24,16 @@ module OpenapiFirst
|
|
|
22
24
|
def call(env)
|
|
23
25
|
env[OPERATION] = nil
|
|
24
26
|
response = call_router(env)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return @parent_app.call(env) if @parent_app # This should only happen if used via OpenapiFirst.middlware
|
|
27
|
+
if env[OPERATION].nil?
|
|
28
|
+
return @parent_app.call(env) if @parent_app # This should only happen if used via OpenapiFirst.middleware
|
|
28
29
|
|
|
29
30
|
raise_error(env) if @raise
|
|
31
|
+
|
|
32
|
+
return @app.call(env) if @not_found == :continue
|
|
30
33
|
end
|
|
31
34
|
response
|
|
32
35
|
end
|
|
33
36
|
|
|
34
|
-
UNKNOWN_ROUTE_STATUS = [404, 405].freeze
|
|
35
37
|
ORIGINAL_PATH = 'openapi_first.path_info'
|
|
36
38
|
|
|
37
39
|
private
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openapi_first
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.12.
|
|
4
|
+
version: 0.12.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andreas Haller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-08-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: deep_merge
|