openapi_first 1.0.0 → 1.1.1
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/CHANGELOG.md +10 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +74 -3
- data/README.md +72 -15
- data/lib/openapi_first/body_parser.rb +6 -2
- data/lib/openapi_first/definition/operation.rb +47 -26
- data/lib/openapi_first/definition/request_body.rb +28 -26
- data/lib/openapi_first/errors.rb +1 -0
- data/lib/openapi_first/failure.rb +1 -1
- data/lib/openapi_first/middlewares/response_validation.rb +6 -3
- data/lib/openapi_first/plugins/default/error_response.rb +1 -1
- data/lib/openapi_first/plugins/jsonapi/error_response.rb +2 -1
- data/lib/openapi_first/request_validation/validator.rb +13 -13
- data/lib/openapi_first/response_validation/validator.rb +22 -26
- data/lib/openapi_first/runtime_request.rb +19 -8
- data/lib/openapi_first/runtime_response.rb +47 -3
- data/lib/openapi_first/schema.rb +0 -4
- data/lib/openapi_first/version.rb +1 -1
- metadata +2 -7
- data/lib/openapi_first/definition/cookie_parameters.rb +0 -12
- data/lib/openapi_first/definition/header_parameters.rb +0 -12
- data/lib/openapi_first/definition/parameters.rb +0 -47
- data/lib/openapi_first/definition/path_parameters.rb +0 -12
- data/lib/openapi_first/definition/query_parameters.rb +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bb6d0ee4dbe98020ef124e79a99ced0d0111b1e2891cc8cb3ed8bb697973d2b
|
|
4
|
+
data.tar.gz: 77ce896a68f885614f64fd680af0dde1860c07ae772ce7d5f7d1b75b5abb4528
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 841e32068646969d92ab26fff9c332e849056463c99805c8e0dbbb437918113a09750fb5ceffd3940716911ea50bc20685acbcd862aa6acc270e43fe43675c87
|
|
7
|
+
data.tar.gz: d9a225b3e3119512fc3ed585f00f6f915e21f3199206f520d20733999441567e651fcb129588092c4e7ea9dcc4ce1e77c24365b04b8a8d9d232b8a1a5cd8e1da
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.1
|
|
4
|
+
|
|
5
|
+
- Fix reading response body for example when running Rails (`ActionDispatch::Response::RackBody`)
|
|
6
|
+
|
|
7
|
+
## 1.1.0
|
|
8
|
+
|
|
9
|
+
- Add `known?`, `status`, `body`, `headers`, `content_type` methods to inspect the parsed response (`RuntimeResponse`)
|
|
10
|
+
- Add `OpenapiFirst::ParseError` which is raised by low-level interfaces like `request.body` if the body could not be parsed.
|
|
11
|
+
- Add "code" field to errors in JSON:API error response
|
|
12
|
+
|
|
3
13
|
## 1.0.0
|
|
4
14
|
|
|
5
15
|
- Breaking: The default error uses application/problem+json content-type
|
data/Gemfile
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
# Specify your gem's dependencies in openapi_first.gemspec
|
|
6
5
|
gemspec
|
|
7
6
|
|
|
8
7
|
gem 'rack', '>= 3.0.0'
|
|
8
|
+
gem 'rackup'
|
|
9
9
|
|
|
10
10
|
group :test, :development do
|
|
11
|
+
gem 'actionpack'
|
|
11
12
|
gem 'bundler'
|
|
12
13
|
gem 'rack-test'
|
|
13
14
|
gem 'rake'
|
|
14
15
|
gem 'rspec'
|
|
15
16
|
gem 'rubocop'
|
|
17
|
+
gem 'simplecov'
|
|
16
18
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
openapi_first (1.
|
|
4
|
+
openapi_first (1.1.1)
|
|
5
5
|
json_refs (~> 0.1, >= 0.1.7)
|
|
6
6
|
json_schemer (~> 2.1.0)
|
|
7
7
|
multi_json (~> 1.15)
|
|
@@ -12,10 +12,48 @@ PATH
|
|
|
12
12
|
GEM
|
|
13
13
|
remote: https://rubygems.org/
|
|
14
14
|
specs:
|
|
15
|
+
actionpack (7.1.2)
|
|
16
|
+
actionview (= 7.1.2)
|
|
17
|
+
activesupport (= 7.1.2)
|
|
18
|
+
nokogiri (>= 1.8.5)
|
|
19
|
+
racc
|
|
20
|
+
rack (>= 2.2.4)
|
|
21
|
+
rack-session (>= 1.0.1)
|
|
22
|
+
rack-test (>= 0.6.3)
|
|
23
|
+
rails-dom-testing (~> 2.2)
|
|
24
|
+
rails-html-sanitizer (~> 1.6)
|
|
25
|
+
actionview (7.1.2)
|
|
26
|
+
activesupport (= 7.1.2)
|
|
27
|
+
builder (~> 3.1)
|
|
28
|
+
erubi (~> 1.11)
|
|
29
|
+
rails-dom-testing (~> 2.2)
|
|
30
|
+
rails-html-sanitizer (~> 1.6)
|
|
31
|
+
activesupport (7.1.2)
|
|
32
|
+
base64
|
|
33
|
+
bigdecimal
|
|
34
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
35
|
+
connection_pool (>= 2.2.5)
|
|
36
|
+
drb
|
|
37
|
+
i18n (>= 1.6, < 2)
|
|
38
|
+
minitest (>= 5.1)
|
|
39
|
+
mutex_m
|
|
40
|
+
tzinfo (~> 2.0)
|
|
15
41
|
ast (2.4.2)
|
|
42
|
+
base64 (0.2.0)
|
|
43
|
+
bigdecimal (3.1.5)
|
|
44
|
+
builder (3.2.4)
|
|
45
|
+
concurrent-ruby (1.2.2)
|
|
46
|
+
connection_pool (2.4.1)
|
|
47
|
+
crass (1.0.6)
|
|
16
48
|
diff-lcs (1.5.0)
|
|
49
|
+
docile (1.4.0)
|
|
50
|
+
drb (2.2.0)
|
|
51
|
+
ruby2_keywords
|
|
52
|
+
erubi (1.12.0)
|
|
17
53
|
hana (1.3.7)
|
|
18
54
|
hansi (0.2.1)
|
|
55
|
+
i18n (1.14.1)
|
|
56
|
+
concurrent-ruby (~> 1.0)
|
|
19
57
|
json (2.7.1)
|
|
20
58
|
json_refs (0.1.8)
|
|
21
59
|
hana
|
|
@@ -24,26 +62,47 @@ GEM
|
|
|
24
62
|
regexp_parser (~> 2.0)
|
|
25
63
|
simpleidn (~> 0.2)
|
|
26
64
|
language_server-protocol (3.17.0.3)
|
|
65
|
+
loofah (2.22.0)
|
|
66
|
+
crass (~> 1.0.2)
|
|
67
|
+
nokogiri (>= 1.12.0)
|
|
68
|
+
minitest (5.21.1)
|
|
27
69
|
multi_json (1.15.0)
|
|
28
70
|
mustermann (3.0.0)
|
|
29
71
|
ruby2_keywords (~> 0.0.1)
|
|
30
72
|
mustermann-contrib (3.0.0)
|
|
31
73
|
hansi (~> 0.2.0)
|
|
32
74
|
mustermann (= 3.0.0)
|
|
75
|
+
mutex_m (0.2.0)
|
|
76
|
+
nokogiri (1.16.0-arm64-darwin)
|
|
77
|
+
racc (~> 1.4)
|
|
78
|
+
nokogiri (1.16.0-x86_64-linux)
|
|
79
|
+
racc (~> 1.4)
|
|
33
80
|
openapi_parameters (0.3.2)
|
|
34
81
|
rack (>= 2.2)
|
|
35
82
|
zeitwerk (~> 2.6)
|
|
36
83
|
parallel (1.24.0)
|
|
37
|
-
parser (3.3.0.
|
|
84
|
+
parser (3.3.0.3)
|
|
38
85
|
ast (~> 2.4.1)
|
|
39
86
|
racc
|
|
40
87
|
racc (1.7.3)
|
|
41
88
|
rack (3.0.8)
|
|
89
|
+
rack-session (2.0.0)
|
|
90
|
+
rack (>= 3.0.0)
|
|
42
91
|
rack-test (2.1.0)
|
|
43
92
|
rack (>= 1.3)
|
|
93
|
+
rackup (2.1.0)
|
|
94
|
+
rack (>= 3)
|
|
95
|
+
webrick (~> 1.8)
|
|
96
|
+
rails-dom-testing (2.2.0)
|
|
97
|
+
activesupport (>= 5.0.0)
|
|
98
|
+
minitest
|
|
99
|
+
nokogiri (>= 1.6)
|
|
100
|
+
rails-html-sanitizer (1.6.0)
|
|
101
|
+
loofah (~> 2.21)
|
|
102
|
+
nokogiri (~> 1.14)
|
|
44
103
|
rainbow (3.1.1)
|
|
45
104
|
rake (13.1.0)
|
|
46
|
-
regexp_parser (2.
|
|
105
|
+
regexp_parser (2.9.0)
|
|
47
106
|
rexml (3.2.6)
|
|
48
107
|
rspec (3.12.0)
|
|
49
108
|
rspec-core (~> 3.12.0)
|
|
@@ -73,12 +132,21 @@ GEM
|
|
|
73
132
|
parser (>= 3.2.1.0)
|
|
74
133
|
ruby-progressbar (1.13.0)
|
|
75
134
|
ruby2_keywords (0.0.5)
|
|
135
|
+
simplecov (0.22.0)
|
|
136
|
+
docile (~> 1.1)
|
|
137
|
+
simplecov-html (~> 0.11)
|
|
138
|
+
simplecov_json_formatter (~> 0.1)
|
|
139
|
+
simplecov-html (0.12.3)
|
|
140
|
+
simplecov_json_formatter (0.1.4)
|
|
76
141
|
simpleidn (0.2.1)
|
|
77
142
|
unf (~> 0.1.4)
|
|
143
|
+
tzinfo (2.0.6)
|
|
144
|
+
concurrent-ruby (~> 1.0)
|
|
78
145
|
unf (0.1.4)
|
|
79
146
|
unf_ext
|
|
80
147
|
unf_ext (0.0.9.1)
|
|
81
148
|
unicode-display_width (2.5.0)
|
|
149
|
+
webrick (1.8.1)
|
|
82
150
|
zeitwerk (2.6.12)
|
|
83
151
|
|
|
84
152
|
PLATFORMS
|
|
@@ -87,13 +155,16 @@ PLATFORMS
|
|
|
87
155
|
x86_64-linux
|
|
88
156
|
|
|
89
157
|
DEPENDENCIES
|
|
158
|
+
actionpack
|
|
90
159
|
bundler
|
|
91
160
|
openapi_first!
|
|
92
161
|
rack (>= 3.0.0)
|
|
93
162
|
rack-test
|
|
163
|
+
rackup
|
|
94
164
|
rake
|
|
95
165
|
rspec
|
|
96
166
|
rubocop
|
|
167
|
+
simplecov
|
|
97
168
|
|
|
98
169
|
BUNDLED WITH
|
|
99
170
|
2.3.10
|
data/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# openapi_first
|
|
2
2
|
|
|
3
|
-
OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description. It supports OpenAPI 3.0 and 3.1. It offers request and response validation
|
|
4
|
-
|
|
5
|
-
This makes your API description reliable, reason about API design and use various tooling on top of OpenAPI.
|
|
3
|
+
OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description. It supports OpenAPI 3.0 and 3.1. It offers request and response validation and it ensures that your implementation follows exactly the API description.
|
|
6
4
|
|
|
7
5
|
## Contents
|
|
8
6
|
|
|
@@ -10,8 +8,12 @@ This makes your API description reliable, reason about API design and use variou
|
|
|
10
8
|
|
|
11
9
|
- [Manual use](#manual-use)
|
|
12
10
|
- [Rack Middlewares](#rack-middlewares)
|
|
11
|
+
- [Request validation](#request-validation)
|
|
12
|
+
- [Response validation](#response-validation)
|
|
13
13
|
- [Configuration](#configuration)
|
|
14
14
|
- [Development](#development)
|
|
15
|
+
- [Benchmarks](#benchmarks)
|
|
16
|
+
- [Contributing](#contributing)
|
|
15
17
|
|
|
16
18
|
<!-- /TOC -->
|
|
17
19
|
|
|
@@ -30,17 +32,21 @@ Validate request / response:
|
|
|
30
32
|
```ruby
|
|
31
33
|
|
|
32
34
|
# Find the request
|
|
33
|
-
rack_request = Rack::Request.new(env)
|
|
35
|
+
rack_request = Rack::Request.new(env) # GET /pets/42
|
|
34
36
|
request = definition.request(rack_request)
|
|
35
37
|
|
|
36
38
|
# Inspect the request and access parsed parameters
|
|
37
39
|
request.known? # Is the request defined in the API description?
|
|
38
|
-
request.
|
|
39
|
-
request.
|
|
40
|
-
request.
|
|
40
|
+
request.content_type
|
|
41
|
+
request.body # alias: parsed_body
|
|
42
|
+
request.path_parameters # => { "pet_id" => 42 }
|
|
43
|
+
request.query_parameters # alias: query
|
|
41
44
|
request.params # Merged path and query parameters
|
|
42
45
|
request.headers
|
|
43
46
|
request.cookies
|
|
47
|
+
request.request_method # => "get"
|
|
48
|
+
request.path # => "/pets/42"
|
|
49
|
+
request.path_definition # => "/pets/{pet_id}"
|
|
44
50
|
|
|
45
51
|
# Validate the request
|
|
46
52
|
request.validate # Returns OpenapiFirst:::Failure if validation fails
|
|
@@ -50,8 +56,15 @@ request.validate! # Raises OpenapiFirst::RequestInvalidError or OpenapiFirst::No
|
|
|
50
56
|
rack_response = Rack::Response[*app.call(env)]
|
|
51
57
|
response = request.response(rack_response) # or definition.response(rack_request, rack_response)
|
|
52
58
|
|
|
59
|
+
# Inspect the response
|
|
60
|
+
response.known? # Is the response defined in the API description?
|
|
61
|
+
response.status # => 200
|
|
62
|
+
response.content_type
|
|
63
|
+
response.body
|
|
64
|
+
request.headers # parsed response headers
|
|
65
|
+
|
|
53
66
|
# Validate response
|
|
54
|
-
response.validate # Returns OpenapiFirst::Failure
|
|
67
|
+
response.validate # Returns OpenapiFirst::Failure if validation fails
|
|
55
68
|
response.validate! # Raises OpenapiFirst::ResponseInvalidError or OpenapiFirst::ResponseNotFoundError if validation fails
|
|
56
69
|
```
|
|
57
70
|
|
|
@@ -73,13 +86,13 @@ use OpenapiFirst::Middlewares::RequestValidation, spec: 'openapi.yaml'
|
|
|
73
86
|
|
|
74
87
|
#### Options
|
|
75
88
|
|
|
76
|
-
| Name | Possible values
|
|
77
|
-
| :---------------- |
|
|
78
|
-
| `spec:` |
|
|
79
|
-
| `raise_error:` | `false` (default), `true`
|
|
80
|
-
| `error_response:` | `:default` (default), `:
|
|
89
|
+
| Name | Possible values | Description |
|
|
90
|
+
| :---------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
|
|
92
|
+
| `raise_error:` | `false` (default), `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` or `OpenapiFirst::NotFoundError` instead of returning 4xx. |
|
|
93
|
+
| `error_response:` | `:default` (default), `:jsonapi`, Your implementation of `ErrorResponse` |
|
|
81
94
|
|
|
82
|
-
Here
|
|
95
|
+
Here in an example response body about an invalid request body. See also [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457).
|
|
83
96
|
|
|
84
97
|
```json
|
|
85
98
|
http-status: 400
|
|
@@ -108,6 +121,50 @@ content-type: "application/problem+json"
|
|
|
108
121
|
}
|
|
109
122
|
```
|
|
110
123
|
|
|
124
|
+
openapi_first offers a [JSON:API](https://jsonapi.org/) error response as well:
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
use OpenapiFirst::Middlewares::RequestValidation, spec: 'openapi.yaml, error_response: :jsonapi'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Here is an example error response:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
// http-status: 400
|
|
134
|
+
// content-type: "application/vnd.api+json"
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
"errors": [
|
|
138
|
+
{
|
|
139
|
+
"status": "400",
|
|
140
|
+
"source": {
|
|
141
|
+
"pointer": "/data/name"
|
|
142
|
+
},
|
|
143
|
+
"title": "value at `/data/name` is not a string",
|
|
144
|
+
"code": "string"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"status": "400",
|
|
148
|
+
"source": {
|
|
149
|
+
"pointer": "/data/numberOfLegs"
|
|
150
|
+
},
|
|
151
|
+
"title": "number at `/data/numberOfLegs` is less than: 2",
|
|
152
|
+
"code": "minimum"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"status": "400",
|
|
156
|
+
"source": {
|
|
157
|
+
"pointer": "/data"
|
|
158
|
+
},
|
|
159
|
+
"title": "object at `/data` is missing required properties: mandatory",
|
|
160
|
+
"code": "required"
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
You can build your own custom error response with `error_response: MyCustomClass` that implements `OpenapiFirst::ErrorResponse`.
|
|
167
|
+
|
|
111
168
|
#### readOnly / writeOnly properties
|
|
112
169
|
|
|
113
170
|
Request validation fails if request includes a property with `readOnly: true`.
|
|
@@ -135,7 +192,7 @@ You can configure default options globally:
|
|
|
135
192
|
```ruby
|
|
136
193
|
OpenapiFirst.configure do |config|
|
|
137
194
|
# Specify which plugin is used to render error responses returned by the request validation middleware (defaults to :default)
|
|
138
|
-
config.request_validation_error_response = :
|
|
195
|
+
config.request_validation_error_response = :jsonapi
|
|
139
196
|
# Configure if the response validation middleware should raise an exception (defaults to false)
|
|
140
197
|
config.request_validation_raise_error = true
|
|
141
198
|
end
|
|
@@ -4,7 +4,11 @@ require 'multi_json'
|
|
|
4
4
|
|
|
5
5
|
module OpenapiFirst
|
|
6
6
|
class BodyParser
|
|
7
|
-
|
|
7
|
+
def self.const_missing(const_name)
|
|
8
|
+
super unless const_name == :ParsingError
|
|
9
|
+
warn 'DEPRECATION WARNING: OpenapiFirst::BodyParser::ParsingError is deprecated. Use OpenapiFirst::ParseError instead.' # rubocop:disable Layout/LineLength
|
|
10
|
+
OpenapiFirst::ParseError
|
|
11
|
+
end
|
|
8
12
|
|
|
9
13
|
def parse(request, content_type)
|
|
10
14
|
body = read_body(request)
|
|
@@ -15,7 +19,7 @@ module OpenapiFirst
|
|
|
15
19
|
|
|
16
20
|
body
|
|
17
21
|
rescue MultiJson::ParseError
|
|
18
|
-
raise
|
|
22
|
+
raise ParseError, 'Failed to parse body as JSON'
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
private
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'forwardable'
|
|
4
4
|
require 'set'
|
|
5
|
+
require 'openapi_parameters'
|
|
5
6
|
require_relative 'request_body'
|
|
6
|
-
require_relative 'query_parameters'
|
|
7
|
-
require_relative 'header_parameters'
|
|
8
|
-
require_relative 'path_parameters'
|
|
9
|
-
require_relative 'cookie_parameters'
|
|
10
7
|
require_relative 'responses'
|
|
11
8
|
|
|
12
9
|
module OpenapiFirst
|
|
@@ -20,8 +17,6 @@ module OpenapiFirst
|
|
|
20
17
|
WRITE_METHODS = Set.new(%w[post put patch delete]).freeze
|
|
21
18
|
private_constant :WRITE_METHODS
|
|
22
19
|
|
|
23
|
-
attr_reader :path, :method, :openapi_version
|
|
24
|
-
|
|
25
20
|
def initialize(path, request_method, path_item_object, openapi_version:)
|
|
26
21
|
@path = path
|
|
27
22
|
@method = request_method
|
|
@@ -30,6 +25,9 @@ module OpenapiFirst
|
|
|
30
25
|
@operation_object = @path_item_object[request_method]
|
|
31
26
|
end
|
|
32
27
|
|
|
28
|
+
attr_reader :path, :method, :openapi_version
|
|
29
|
+
alias request_method method
|
|
30
|
+
|
|
33
31
|
def operation_id
|
|
34
32
|
operation_object['operationId']
|
|
35
33
|
end
|
|
@@ -66,34 +64,63 @@ module OpenapiFirst
|
|
|
66
64
|
@name ||= "#{method.upcase} #{path} (#{operation_id})"
|
|
67
65
|
end
|
|
68
66
|
|
|
69
|
-
def query_parameters
|
|
70
|
-
@query_parameters ||= build_parameters(all_parameters.filter { |p| p['in'] == 'query' }, QueryParameters)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
67
|
def path_parameters
|
|
74
|
-
|
|
68
|
+
all_parameters['path']
|
|
75
69
|
end
|
|
76
70
|
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
def query_parameters
|
|
72
|
+
all_parameters['query']
|
|
73
|
+
end
|
|
79
74
|
|
|
80
75
|
def header_parameters
|
|
81
|
-
|
|
76
|
+
all_parameters['header']
|
|
82
77
|
end
|
|
83
78
|
|
|
84
79
|
def cookie_parameters
|
|
85
|
-
|
|
80
|
+
all_parameters['cookie']
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def path_parameters_schema
|
|
84
|
+
@path_parameters_schema ||= build_schema(path_parameters)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def query_parameters_schema
|
|
88
|
+
@query_parameters_schema ||= build_schema(query_parameters)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def header_parameters_schema
|
|
92
|
+
@header_parameters_schema ||= build_schema(header_parameters)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def cookie_parameters_schema
|
|
96
|
+
@cookie_parameters_schema ||= build_schema(cookie_parameters)
|
|
86
97
|
end
|
|
87
98
|
|
|
88
99
|
private
|
|
89
100
|
|
|
101
|
+
IGNORED_HEADERS = Set['Content-Type', 'Accept', 'Authorization'].freeze
|
|
102
|
+
private_constant :IGNORED_HEADERS
|
|
103
|
+
|
|
90
104
|
def all_parameters
|
|
91
|
-
@all_parameters ||=
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
@all_parameters ||= (@path_item_object.fetch('parameters', []) + operation_object.fetch('parameters', []))
|
|
106
|
+
.reject { |p| p['in'] == 'header' && IGNORED_HEADERS.include?(p['name']) }
|
|
107
|
+
.group_by { _1['in'] }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def build_schema(parameters)
|
|
111
|
+
return unless parameters&.any?
|
|
112
|
+
|
|
113
|
+
init_schema = {
|
|
114
|
+
'type' => 'object',
|
|
115
|
+
'properties' => {},
|
|
116
|
+
'required' => []
|
|
117
|
+
}
|
|
118
|
+
schema = parameters.each_with_object(init_schema) do |parameter_def, result|
|
|
119
|
+
parameter = OpenapiParameters::Parameter.new(parameter_def)
|
|
120
|
+
result['properties'][parameter.name] = parameter.schema if parameter.schema
|
|
121
|
+
result['required'] << parameter.name if parameter.required?
|
|
96
122
|
end
|
|
123
|
+
Schema.new(schema, openapi_version: @openapi_version)
|
|
97
124
|
end
|
|
98
125
|
|
|
99
126
|
def responses
|
|
@@ -105,12 +132,6 @@ module OpenapiFirst
|
|
|
105
132
|
def build_parameters(parameters, klass)
|
|
106
133
|
klass.new(parameters, openapi_version:) if parameters.any?
|
|
107
134
|
end
|
|
108
|
-
|
|
109
|
-
def find_header_parameters
|
|
110
|
-
all_parameters.filter do |p|
|
|
111
|
-
p['in'] == 'header' && !IGNORED_HEADERS.include?(p['name'])
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
135
|
end
|
|
115
136
|
end
|
|
116
137
|
end
|
|
@@ -3,40 +3,42 @@
|
|
|
3
3
|
require_relative '../schema'
|
|
4
4
|
|
|
5
5
|
module OpenapiFirst
|
|
6
|
-
class
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
class Definition
|
|
7
|
+
class RequestBody
|
|
8
|
+
def initialize(request_body_object, operation)
|
|
9
|
+
@request_body_object = request_body_object
|
|
10
|
+
@operation = operation
|
|
11
|
+
end
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
def description
|
|
14
|
+
@request_body_object['description']
|
|
15
|
+
end
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
def required?
|
|
18
|
+
!!@request_body_object['required']
|
|
19
|
+
end
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
def schema_for(content_type)
|
|
22
|
+
content = @request_body_object['content']
|
|
23
|
+
return unless content&.any?
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
content_schemas&.fetch(content_type) do
|
|
26
|
+
type = content_type.split(';')[0]
|
|
27
|
+
content_schemas[type] || content_schemas["#{type.split('/')[0]}/*"] || content_schemas['*/*']
|
|
28
|
+
end
|
|
27
29
|
end
|
|
28
|
-
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
private
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
def content_schemas
|
|
34
|
+
@content_schemas ||= @request_body_object['content']&.each_with_object({}) do |kv, result|
|
|
35
|
+
type, media_type = kv
|
|
36
|
+
schema_object = media_type['schema']
|
|
37
|
+
next unless schema_object
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
result[type] = Schema.new(schema_object, write: @operation.write?,
|
|
40
|
+
openapi_version: @operation.openapi_version)
|
|
41
|
+
end
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
end
|
data/lib/openapi_first/errors.rb
CHANGED
|
@@ -20,7 +20,7 @@ module OpenapiFirst
|
|
|
20
20
|
private_constant :TYPES
|
|
21
21
|
|
|
22
22
|
# @param error_type [Symbol] See Failure::TYPES.keys
|
|
23
|
-
# @param errors [Array<OpenapiFirst::Schema::
|
|
23
|
+
# @param errors [Array<OpenapiFirst::Schema::ValidationError>]
|
|
24
24
|
def self.fail!(error_type, message: nil, errors: nil)
|
|
25
25
|
throw FAILURE, new(
|
|
26
26
|
error_type,
|
|
@@ -19,10 +19,13 @@ module OpenapiFirst
|
|
|
19
19
|
|
|
20
20
|
def call(env)
|
|
21
21
|
request = find_request(env)
|
|
22
|
-
|
|
23
|
-
request.response(response).validate!
|
|
22
|
+
status, headers, body = @app.call(env)
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
body = body.to_ary if body.respond_to?(:to_ary)
|
|
25
|
+
|
|
26
|
+
request.response(Rack::Response[status, headers, body]).validate!
|
|
27
|
+
|
|
28
|
+
[status, headers, body]
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
private
|
|
@@ -16,7 +16,7 @@ module OpenapiFirst
|
|
|
16
16
|
invalid_query: 'Bad Query Parameter',
|
|
17
17
|
invalid_header: 'Bad Request Header',
|
|
18
18
|
invalid_path: 'Bad Request Path',
|
|
19
|
-
invalid_cookie: '
|
|
19
|
+
invalid_cookie: 'Bad Request Cookie'
|
|
20
20
|
}.freeze
|
|
21
21
|
private_constant :TITLES
|
|
22
22
|
|
|
@@ -38,34 +38,34 @@ module OpenapiFirst
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def validate_path_params!(request)
|
|
41
|
-
|
|
42
|
-
return unless
|
|
41
|
+
schema = operation.path_parameters_schema
|
|
42
|
+
return unless schema
|
|
43
43
|
|
|
44
|
-
validation =
|
|
44
|
+
validation = schema.validate(request.path_parameters)
|
|
45
45
|
Failure.fail!(:invalid_path, errors: validation.errors) if validation.error?
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def validate_query_params!(request)
|
|
49
|
-
|
|
50
|
-
return unless
|
|
49
|
+
schema = operation.query_parameters_schema
|
|
50
|
+
return unless schema
|
|
51
51
|
|
|
52
|
-
validation =
|
|
52
|
+
validation = schema.validate(request.query)
|
|
53
53
|
Failure.fail!(:invalid_query, errors: validation.errors) if validation.error?
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def validate_cookie_params!(request)
|
|
57
|
-
|
|
58
|
-
return unless
|
|
57
|
+
schema = operation.cookie_parameters_schema
|
|
58
|
+
return unless schema
|
|
59
59
|
|
|
60
|
-
validation =
|
|
60
|
+
validation = schema.validate(request.cookies)
|
|
61
61
|
Failure.fail!(:invalid_cookie, errors: validation.errors) if validation.error?
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def validate_header_params!(request)
|
|
65
|
-
|
|
66
|
-
return unless
|
|
65
|
+
schema = operation.header_parameters_schema
|
|
66
|
+
return unless schema
|
|
67
67
|
|
|
68
|
-
validation =
|
|
68
|
+
validation = schema.validate(request.headers)
|
|
69
69
|
Failure.fail!(:invalid_header, errors: validation.errors) if validation.error?
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ module OpenapiFirst
|
|
|
73
73
|
return unless operation.request_body
|
|
74
74
|
|
|
75
75
|
RequestBodyValidator.new(operation).validate!(request.body, request.content_type)
|
|
76
|
-
rescue
|
|
76
|
+
rescue ParseError => e
|
|
77
77
|
Failure.fail!(:invalid_body, message: e.message)
|
|
78
78
|
end
|
|
79
79
|
end
|
|
@@ -9,14 +9,14 @@ module OpenapiFirst
|
|
|
9
9
|
@operation = operation
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def validate(
|
|
12
|
+
def validate(runtime_response)
|
|
13
13
|
return unless operation
|
|
14
14
|
|
|
15
|
-
response = Rack::Response[*rack_response.to_a]
|
|
16
15
|
catch Failure::FAILURE do
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
validate_defined(runtime_response)
|
|
17
|
+
response_definition = runtime_response.response_definition
|
|
18
|
+
validate_response_body(response_definition.content_schema, runtime_response)
|
|
19
|
+
validate_response_headers(response_definition.headers, runtime_response.headers)
|
|
20
20
|
nil
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -25,37 +25,40 @@ module OpenapiFirst
|
|
|
25
25
|
|
|
26
26
|
attr_reader :operation
|
|
27
27
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
return response if response
|
|
28
|
+
def validate_defined(runtime_response)
|
|
29
|
+
return if runtime_response.known?
|
|
31
30
|
|
|
32
|
-
unless
|
|
33
|
-
message = "Response status '#{status}' not found for '#{
|
|
31
|
+
unless runtime_response.known_status?
|
|
32
|
+
message = "Response status '#{runtime_response.status}' not found for '#{runtime_response.name}'"
|
|
34
33
|
Failure.fail!(:response_not_found, message:)
|
|
35
34
|
end
|
|
35
|
+
|
|
36
|
+
content_type = runtime_response.content_type
|
|
36
37
|
if content_type.nil? || content_type.empty?
|
|
37
|
-
message = "Content-Type for '#{
|
|
38
|
+
message = "Content-Type for '#{runtime_response.name}' must not be empty"
|
|
38
39
|
Failure.fail!(:invalid_response_header, message:)
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
message = "Content-Type '#{content_type}' is not defined for '#{
|
|
42
|
+
message = "Content-Type '#{content_type}' is not defined for '#{runtime_response.name}'"
|
|
42
43
|
Failure.fail!(:invalid_response_header, message:)
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
def validate_response_body(schema,
|
|
46
|
+
def validate_response_body(schema, runtime_response)
|
|
46
47
|
return unless schema
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
begin
|
|
50
|
+
parsed_body = runtime_response.body
|
|
51
|
+
rescue ParseError => e
|
|
52
|
+
Failure.fail!(:invalid_response_body, message: e.message)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
validation = schema.validate(parsed_body)
|
|
52
56
|
Failure.fail!(:invalid_response_body, errors: validation.errors) if validation.error?
|
|
53
57
|
end
|
|
54
58
|
|
|
55
|
-
def validate_response_headers(response_header_definitions,
|
|
59
|
+
def validate_response_headers(response_header_definitions, unpacked_headers)
|
|
56
60
|
return unless response_header_definitions
|
|
57
61
|
|
|
58
|
-
unpacked_headers = unpack_response_headers(response_header_definitions, response_headers)
|
|
59
62
|
response_header_definitions.each do |name, definition|
|
|
60
63
|
next if name == 'Content-Type'
|
|
61
64
|
|
|
@@ -84,13 +87,6 @@ module OpenapiFirst
|
|
|
84
87
|
errors: validation_result.errors)
|
|
85
88
|
end
|
|
86
89
|
|
|
87
|
-
def unpack_response_headers(response_header_definitions, response_headers)
|
|
88
|
-
headers_as_parameters = response_header_definitions.map do |name, definition|
|
|
89
|
-
definition.merge('name' => name, 'in' => 'header')
|
|
90
|
-
end
|
|
91
|
-
OpenapiParameters::Header.new(headers_as_parameters).unpack(response_headers)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
90
|
def load_json(string)
|
|
95
91
|
MultiJson.load(string)
|
|
96
92
|
rescue MultiJson::ParseError
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'forwardable'
|
|
4
|
+
require 'openapi_parameters'
|
|
4
5
|
require_relative 'runtime_response'
|
|
5
6
|
require_relative 'body_parser'
|
|
6
7
|
require_relative 'request_validation/validator'
|
|
@@ -17,8 +18,11 @@ module OpenapiFirst
|
|
|
17
18
|
@original_path_params = path_params
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
def_delegators :@request, :content_type, :media_type
|
|
21
|
-
def_delegators :@operation, :operation_id
|
|
21
|
+
def_delegators :@request, :content_type, :media_type, :path
|
|
22
|
+
def_delegators :@operation, :operation_id, :request_method
|
|
23
|
+
def_delegator :@path_item, :path, :path_definition
|
|
24
|
+
|
|
25
|
+
attr_reader :path_item
|
|
22
26
|
|
|
23
27
|
def known?
|
|
24
28
|
known_path? && known_request_method?
|
|
@@ -38,25 +42,32 @@ module OpenapiFirst
|
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
def path_parameters
|
|
45
|
+
return {} unless operation.path_parameters
|
|
46
|
+
|
|
41
47
|
@path_parameters ||=
|
|
42
|
-
operation.path_parameters
|
|
48
|
+
OpenapiParameters::Path.new(operation.path_parameters).unpack(@original_path_params) || {}
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
def query
|
|
52
|
+
return {} unless operation.query_parameters
|
|
53
|
+
|
|
46
54
|
@query ||=
|
|
47
|
-
operation.query_parameters
|
|
55
|
+
OpenapiParameters::Query.new(operation.query_parameters).unpack(request.env[Rack::QUERY_STRING]) || {}
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
alias query_parameters query
|
|
51
59
|
|
|
52
60
|
def headers
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
return {} unless operation.header_parameters
|
|
62
|
+
|
|
63
|
+
@headers ||= OpenapiParameters::Header.new(operation.header_parameters).unpack_env(request.env) || {}
|
|
55
64
|
end
|
|
56
65
|
|
|
57
66
|
def cookies
|
|
67
|
+
return {} unless operation.cookie_parameters
|
|
68
|
+
|
|
58
69
|
@cookies ||=
|
|
59
|
-
operation.cookie_parameters
|
|
70
|
+
OpenapiParameters::Cookie.new(operation.cookie_parameters).unpack(request.env[Rack::HTTP_COOKIE]) || {}
|
|
60
71
|
end
|
|
61
72
|
|
|
62
73
|
def body
|
|
@@ -79,6 +90,6 @@ module OpenapiFirst
|
|
|
79
90
|
|
|
80
91
|
private
|
|
81
92
|
|
|
82
|
-
attr_reader :request, :operation
|
|
93
|
+
attr_reader :request, :operation
|
|
83
94
|
end
|
|
84
95
|
end
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
require_relative 'body_parser'
|
|
3
5
|
require_relative 'response_validation/validator'
|
|
4
6
|
|
|
5
7
|
module OpenapiFirst
|
|
6
8
|
class RuntimeResponse
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
7
11
|
def initialize(operation, rack_response)
|
|
8
12
|
@operation = operation
|
|
9
13
|
@rack_response = rack_response
|
|
10
14
|
end
|
|
11
15
|
|
|
16
|
+
def_delegators :@rack_response, :status, :content_type
|
|
17
|
+
def_delegators :@operation, :name
|
|
18
|
+
|
|
19
|
+
def known?
|
|
20
|
+
!!response_definition
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def known_status?
|
|
24
|
+
@operation.response_status_defined?(status)
|
|
25
|
+
end
|
|
26
|
+
|
|
12
27
|
def description
|
|
13
28
|
response_definition&.description
|
|
14
29
|
end
|
|
15
30
|
|
|
31
|
+
def body
|
|
32
|
+
@body ||= content_type =~ /json/i ? load_json(original_body) : original_body
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def headers
|
|
36
|
+
@headers ||= unpack_response_headers
|
|
37
|
+
end
|
|
38
|
+
|
|
16
39
|
def validate
|
|
17
|
-
ResponseValidation::Validator.new(@operation).validate(
|
|
40
|
+
ResponseValidation::Validator.new(@operation).validate(self)
|
|
18
41
|
end
|
|
19
42
|
|
|
20
43
|
def validate!
|
|
@@ -22,10 +45,31 @@ module OpenapiFirst
|
|
|
22
45
|
error&.raise!
|
|
23
46
|
end
|
|
24
47
|
|
|
48
|
+
def response_definition
|
|
49
|
+
@response_definition ||= @operation.response_for(status, content_type)
|
|
50
|
+
end
|
|
51
|
+
|
|
25
52
|
private
|
|
26
53
|
|
|
27
|
-
def
|
|
28
|
-
|
|
54
|
+
def original_body
|
|
55
|
+
buffered_body = String.new
|
|
56
|
+
@rack_response.body.each { |chunk| buffered_body << chunk }
|
|
57
|
+
buffered_body
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def load_json(string)
|
|
61
|
+
MultiJson.load(string)
|
|
62
|
+
rescue MultiJson::ParseError
|
|
63
|
+
raise ParseError, 'Failed to parse response body as JSON'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def unpack_response_headers
|
|
67
|
+
return {} if response_definition&.headers.nil?
|
|
68
|
+
|
|
69
|
+
headers_as_parameters = response_definition.headers.map do |name, definition|
|
|
70
|
+
definition.merge('name' => name, 'in' => 'header')
|
|
71
|
+
end
|
|
72
|
+
OpenapiParameters::Header.new(headers_as_parameters).unpack(@rack_response.headers)
|
|
29
73
|
end
|
|
30
74
|
end
|
|
31
75
|
end
|
data/lib/openapi_first/schema.rb
CHANGED
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: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andreas Haller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-01-
|
|
11
|
+
date: 2024-01-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json_refs
|
|
@@ -133,13 +133,8 @@ files:
|
|
|
133
133
|
- lib/openapi_first/body_parser.rb
|
|
134
134
|
- lib/openapi_first/configuration.rb
|
|
135
135
|
- lib/openapi_first/definition.rb
|
|
136
|
-
- lib/openapi_first/definition/cookie_parameters.rb
|
|
137
|
-
- lib/openapi_first/definition/header_parameters.rb
|
|
138
136
|
- lib/openapi_first/definition/operation.rb
|
|
139
|
-
- lib/openapi_first/definition/parameters.rb
|
|
140
137
|
- lib/openapi_first/definition/path_item.rb
|
|
141
|
-
- lib/openapi_first/definition/path_parameters.rb
|
|
142
|
-
- lib/openapi_first/definition/query_parameters.rb
|
|
143
138
|
- lib/openapi_first/definition/request_body.rb
|
|
144
139
|
- lib/openapi_first/definition/response.rb
|
|
145
140
|
- lib/openapi_first/definition/responses.rb
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'openapi_parameters'
|
|
4
|
-
require_relative 'parameters'
|
|
5
|
-
|
|
6
|
-
module OpenapiFirst
|
|
7
|
-
class CookieParameters < Parameters
|
|
8
|
-
def unpack(env)
|
|
9
|
-
OpenapiParameters::Cookie.new(@parameter_definitions).unpack(env['HTTP_COOKIE'])
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'openapi_parameters'
|
|
4
|
-
require_relative 'parameters'
|
|
5
|
-
|
|
6
|
-
module OpenapiFirst
|
|
7
|
-
class HeaderParameters < Parameters
|
|
8
|
-
def unpack(env)
|
|
9
|
-
OpenapiParameters::Header.new(@parameter_definitions).unpack_env(env)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'forwardable'
|
|
4
|
-
require_relative '../schema'
|
|
5
|
-
|
|
6
|
-
module OpenapiFirst
|
|
7
|
-
class Parameters
|
|
8
|
-
extend Forwardable
|
|
9
|
-
|
|
10
|
-
def initialize(parameter_definitions, openapi_version:)
|
|
11
|
-
@parameter_definitions = parameter_definitions
|
|
12
|
-
@openapi_version = openapi_version
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def_delegators :parameters, :map
|
|
16
|
-
|
|
17
|
-
def empty?
|
|
18
|
-
@parameter_definitions.empty?
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def schema
|
|
22
|
-
@schema ||= build_schema
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def parameters
|
|
26
|
-
@parameter_definitions.map do |parameter_object|
|
|
27
|
-
OpenapiParameters::Parameter.new(parameter_object)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def build_schema
|
|
34
|
-
init_schema = {
|
|
35
|
-
'type' => 'object',
|
|
36
|
-
'properties' => {},
|
|
37
|
-
'required' => []
|
|
38
|
-
}
|
|
39
|
-
schema = @parameter_definitions.each_with_object(init_schema) do |parameter_def, result|
|
|
40
|
-
parameter = OpenapiParameters::Parameter.new(parameter_def)
|
|
41
|
-
result['properties'][parameter.name] = parameter.schema if parameter.schema
|
|
42
|
-
result['required'] << parameter.name if parameter.required?
|
|
43
|
-
end
|
|
44
|
-
Schema.new(schema, openapi_version: @openapi_version)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'openapi_parameters'
|
|
4
|
-
require_relative 'parameters'
|
|
5
|
-
|
|
6
|
-
module OpenapiFirst
|
|
7
|
-
class PathParameters < Parameters
|
|
8
|
-
def unpack(original_path_params)
|
|
9
|
-
OpenapiParameters::Path.new(@parameter_definitions).unpack(original_path_params)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'openapi_parameters'
|
|
4
|
-
require_relative 'parameters'
|
|
5
|
-
|
|
6
|
-
module OpenapiFirst
|
|
7
|
-
class QueryParameters < Parameters
|
|
8
|
-
def unpack(env)
|
|
9
|
-
OpenapiParameters::Query.new(@parameter_definitions).unpack(env['QUERY_STRING'])
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|