scorpio 0.4.5 → 0.6.0
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 +13 -0
- data/LICENSE.md +613 -0
- data/README.md +31 -18
- data/documents/github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0/schema.yaml +30 -22
- data/lib/scorpio/google_api_document.rb +27 -15
- data/lib/scorpio/openapi/document.rb +8 -6
- data/lib/scorpio/openapi/operation.rb +92 -42
- data/lib/scorpio/openapi/operations_scope.rb +13 -11
- data/lib/scorpio/openapi/reference.rb +44 -0
- data/lib/scorpio/openapi/tag.rb +15 -0
- data/lib/scorpio/openapi/v3/server.rb +4 -2
- data/lib/scorpio/openapi.rb +186 -135
- data/lib/scorpio/pickle_adapter.rb +2 -0
- data/lib/scorpio/request.rb +60 -41
- data/lib/scorpio/resource_base.rb +238 -198
- data/lib/scorpio/response.rb +10 -6
- data/lib/scorpio/ur.rb +16 -15
- data/lib/scorpio/version.rb +3 -1
- data/lib/scorpio.rb +5 -6
- data/scorpio.gemspec +16 -23
- metadata +23 -206
- data/.simplecov +0 -1
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -10
- data/bin/documents_to_yml.rb +0 -33
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Scorpio
|
2
4
|
module OpenAPI
|
3
5
|
# An OpenAPI operation
|
@@ -43,37 +45,42 @@ module Scorpio
|
|
43
45
|
end
|
44
46
|
include Configurables
|
45
47
|
|
46
|
-
#
|
48
|
+
# openapi v3?
|
49
|
+
# @return [Boolean]
|
47
50
|
def v3?
|
48
51
|
is_a?(V3::Operation)
|
49
52
|
end
|
50
53
|
|
51
|
-
#
|
54
|
+
# openapi v2?
|
55
|
+
# @return [Boolean]
|
52
56
|
def v2?
|
53
57
|
is_a?(V2::Operation)
|
54
58
|
end
|
55
59
|
|
56
|
-
#
|
60
|
+
# the document whence this operation came
|
61
|
+
# @return [Scorpio::OpenAPI::Document]
|
57
62
|
def openapi_document
|
58
|
-
|
63
|
+
jsi_parent_nodes.detect { |p| p.is_a?(Scorpio::OpenAPI::Document) }
|
59
64
|
end
|
60
65
|
|
66
|
+
# @return [String]
|
61
67
|
def path_template_str
|
62
68
|
return @path_template_str if instance_variable_defined?(:@path_template_str)
|
63
|
-
raise(Bug) unless
|
64
|
-
raise(Bug) unless
|
65
|
-
@path_template_str =
|
69
|
+
raise(Bug) unless jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::PathItem) || jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::PathItem)
|
70
|
+
raise(Bug) unless jsi_parent_node.jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::Paths) || jsi_parent_node.jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::Paths)
|
71
|
+
@path_template_str = jsi_parent_node.jsi_ptr.tokens.last
|
66
72
|
end
|
67
73
|
|
68
|
-
#
|
74
|
+
# the path as an Addressable::Template
|
75
|
+
# @return [Addressable::Template]
|
69
76
|
def path_template
|
70
77
|
return @path_template if instance_variable_defined?(:@path_template)
|
71
78
|
@path_template = Addressable::Template.new(path_template_str)
|
72
79
|
end
|
73
80
|
|
81
|
+
# the URI template, consisting of the base_url concatenated with the path template
|
74
82
|
# @param base_url [#to_str] the base URL to which the path template is appended
|
75
|
-
# @return [Addressable::Template]
|
76
|
-
# concatenated with the path template
|
83
|
+
# @return [Addressable::Template]
|
77
84
|
def uri_template(base_url: self.base_url)
|
78
85
|
unless base_url
|
79
86
|
raise(ArgumentError, "no base_url has been specified for operation #{self}")
|
@@ -83,33 +90,38 @@ module Scorpio
|
|
83
90
|
Addressable::Template.new(File.join(base_url, path_template_str))
|
84
91
|
end
|
85
92
|
|
86
|
-
#
|
87
|
-
#
|
93
|
+
# the HTTP method of this operation as indicated by the attribute name for this operation
|
94
|
+
# from the parent PathItem
|
95
|
+
# @return [String]
|
88
96
|
def http_method
|
89
97
|
return @http_method if instance_variable_defined?(:@http_method)
|
90
|
-
raise(Bug) unless
|
91
|
-
@http_method = jsi_ptr.
|
98
|
+
raise(Bug) unless jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::PathItem) || jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::PathItem)
|
99
|
+
@http_method = jsi_ptr.tokens.last
|
92
100
|
end
|
93
101
|
|
94
|
-
#
|
102
|
+
# a short identifier for this operation appropriate for an error message
|
103
|
+
# @return [String]
|
95
104
|
def human_id
|
96
105
|
operationId || "path: #{path_template_str}, method: #{http_method}"
|
97
106
|
end
|
98
107
|
|
108
|
+
# @param status [String, Integer]
|
99
109
|
# @return [Scorpio::OpenAPI::V3::Response, Scorpio::OpenAPI::V2::Response]
|
100
110
|
def oa_response(status: )
|
101
111
|
status = status.to_s if status.is_a?(Numeric)
|
102
|
-
if
|
103
|
-
_, oa_response =
|
104
|
-
oa_response ||=
|
112
|
+
if responses
|
113
|
+
_, oa_response = responses.detect { |k, v| k.to_s == status }
|
114
|
+
oa_response ||= responses['default']
|
105
115
|
end
|
106
116
|
oa_response
|
107
117
|
end
|
108
118
|
|
119
|
+
# the parameters specified for this operation, plus any others scorpio considers to be parameters.
|
120
|
+
#
|
109
121
|
# this method is not intended to be API-stable at the moment.
|
110
122
|
#
|
111
|
-
# @
|
112
|
-
#
|
123
|
+
# @api private
|
124
|
+
# @return [#to_ary<#to_h>]
|
113
125
|
def inferred_parameters
|
114
126
|
parameters = self.parameters ? self.parameters.to_a.dup : []
|
115
127
|
path_template.variables.each do |var|
|
@@ -127,7 +139,8 @@ module Scorpio
|
|
127
139
|
parameters
|
128
140
|
end
|
129
141
|
|
130
|
-
#
|
142
|
+
# a module with accessor methods for unambiguously named parameters of this operation.
|
143
|
+
# @return [Module]
|
131
144
|
def request_accessor_module
|
132
145
|
return @request_accessor_module if instance_variable_defined?(:@request_accessor_module)
|
133
146
|
@request_accessor_module = begin
|
@@ -136,7 +149,7 @@ module Scorpio
|
|
136
149
|
instance_method_modules = [Request, Request::Configurables]
|
137
150
|
instance_method_names = instance_method_modules.map do |mod|
|
138
151
|
(mod.instance_methods + mod.private_instance_methods).map(&:to_s)
|
139
|
-
end.inject(Set.new,
|
152
|
+
end.inject(Set.new, &:merge)
|
140
153
|
params_by_name.each do |name, params|
|
141
154
|
next if instance_method_names.include?(name)
|
142
155
|
if params.size == 1
|
@@ -149,19 +162,22 @@ module Scorpio
|
|
149
162
|
end
|
150
163
|
end
|
151
164
|
|
152
|
-
#
|
165
|
+
# instantiates a {Scorpio::Request} for this operation.
|
166
|
+
# parameters are all passed to {Scorpio::Request#initialize}.
|
153
167
|
# @return [Scorpio::Request]
|
154
168
|
def build_request(*a, &b)
|
155
169
|
Scorpio::Request.new(self, *a, &b)
|
156
170
|
end
|
157
171
|
|
158
|
-
#
|
172
|
+
# runs a {Scorpio::Request} for this operation, returning a {Scorpio::Ur}.
|
173
|
+
# parameters are all passed to {Scorpio::Request#initialize}.
|
159
174
|
# @return [Scorpio::Ur] response ur
|
160
175
|
def run_ur(*a, &b)
|
161
176
|
build_request(*a, &b).run_ur
|
162
177
|
end
|
163
178
|
|
164
|
-
#
|
179
|
+
# runs a {Scorpio::Request} for this operation - see {Scorpio::Request#run}.
|
180
|
+
# parameters are all passed to {Scorpio::Request#initialize}.
|
165
181
|
# @return response body object
|
166
182
|
def run(*a, &b)
|
167
183
|
build_request(*a, &b).run
|
@@ -174,7 +190,7 @@ module Scorpio
|
|
174
190
|
# Describes a single API operation on a path.
|
175
191
|
#
|
176
192
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject
|
177
|
-
|
193
|
+
module Operation
|
178
194
|
module Configurables
|
179
195
|
def scheme
|
180
196
|
# not applicable; for OpenAPI v3, scheme is specified by servers.
|
@@ -212,17 +228,19 @@ module Scorpio
|
|
212
228
|
requestBody['content'] &&
|
213
229
|
requestBody['content'][media_type] &&
|
214
230
|
requestBody['content'][media_type]['schema']
|
215
|
-
schema_object ? JSI::Schema.
|
231
|
+
schema_object ? JSI::Schema.ensure_schema(schema_object) : nil
|
216
232
|
end
|
217
233
|
|
218
|
-
# @return [
|
234
|
+
# @return [JSI::SchemaSet]
|
219
235
|
def request_schemas
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
236
|
+
JSI::SchemaSet.build do |schemas|
|
237
|
+
if requestBody && requestBody['content']
|
238
|
+
requestBody['content'].each_value do |oa_media_type|
|
239
|
+
if oa_media_type['schema']
|
240
|
+
schemas << oa_media_type['schema']
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
226
244
|
end
|
227
245
|
end
|
228
246
|
|
@@ -232,13 +250,30 @@ module Scorpio
|
|
232
250
|
oa_media_types = oa_response ? oa_response['content'] : nil # Scorpio::OpenAPI::V3::MediaTypes
|
233
251
|
oa_media_type = oa_media_types ? oa_media_types[media_type] : nil # Scorpio::OpenAPI::V3::MediaType
|
234
252
|
oa_schema = oa_media_type ? oa_media_type['schema'] : nil # Scorpio::OpenAPI::V3::Schema
|
235
|
-
oa_schema ? JSI::Schema.
|
253
|
+
oa_schema ? JSI::Schema.ensure_schema(oa_schema) : nil
|
254
|
+
end
|
255
|
+
|
256
|
+
# @return [JSI::SchemaSet]
|
257
|
+
def response_schemas
|
258
|
+
JSI::SchemaSet.build do |schemas|
|
259
|
+
if responses
|
260
|
+
responses.each_value do |oa_response|
|
261
|
+
if oa_response['content']
|
262
|
+
oa_response['content'].each_value do |oa_media_type|
|
263
|
+
if oa_media_type['schema']
|
264
|
+
schemas << oa_media_type['schema']
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
236
271
|
end
|
237
272
|
end
|
238
273
|
end
|
239
274
|
module V2
|
240
275
|
raise(Bug, 'const_defined? Scorpio::OpenAPI::V2::Operation') unless const_defined?(:Operation)
|
241
|
-
|
276
|
+
module Operation
|
242
277
|
module Configurables
|
243
278
|
attr_writer :scheme
|
244
279
|
def scheme
|
@@ -264,7 +299,8 @@ module Scorpio
|
|
264
299
|
end
|
265
300
|
include Configurables
|
266
301
|
|
267
|
-
#
|
302
|
+
# the body parameter
|
303
|
+
# @return [#to_hash]
|
268
304
|
# @raise [Scorpio::OpenAPI::SemanticError] if there's more than one body param
|
269
305
|
def body_parameter
|
270
306
|
body_parameters = (parameters || []).select { |parameter| parameter['in'] == 'body' }
|
@@ -278,19 +314,20 @@ module Scorpio
|
|
278
314
|
end
|
279
315
|
end
|
280
316
|
|
317
|
+
# request schema for the given media_type
|
281
318
|
# @param media_type unused
|
282
|
-
# @return [JSI::Schema]
|
319
|
+
# @return [JSI::Schema]
|
283
320
|
def request_schema(media_type: nil)
|
284
321
|
if body_parameter && body_parameter['schema']
|
285
|
-
JSI::Schema.
|
322
|
+
JSI::Schema.ensure_schema(body_parameter['schema'])
|
286
323
|
else
|
287
324
|
nil
|
288
325
|
end
|
289
326
|
end
|
290
327
|
|
291
|
-
# @return [
|
328
|
+
# @return [JSI::SchemaSet]
|
292
329
|
def request_schemas
|
293
|
-
request_schema ? [request_schema] : []
|
330
|
+
request_schema ? JSI::SchemaSet[request_schema] : JSI::SchemaSet[]
|
294
331
|
end
|
295
332
|
|
296
333
|
# @param status [Integer, String] response status
|
@@ -299,7 +336,20 @@ module Scorpio
|
|
299
336
|
def response_schema(status: , media_type: nil)
|
300
337
|
oa_response = self.oa_response(status: status)
|
301
338
|
oa_response_schema = oa_response ? oa_response['schema'] : nil # Scorpio::OpenAPI::V2::Schema
|
302
|
-
oa_response_schema ? JSI::Schema.
|
339
|
+
oa_response_schema ? JSI::Schema.ensure_schema(oa_response_schema) : nil
|
340
|
+
end
|
341
|
+
|
342
|
+
# @return [JSI::SchemaSet]
|
343
|
+
def response_schemas
|
344
|
+
JSI::SchemaSet.build do |schemas|
|
345
|
+
if responses
|
346
|
+
responses.each_value do |oa_response|
|
347
|
+
if oa_response['schema']
|
348
|
+
schemas << oa_response['schema']
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
303
353
|
end
|
304
354
|
end
|
305
355
|
end
|
@@ -1,13 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Scorpio
|
2
4
|
module OpenAPI
|
3
5
|
# OperationsScope acts as an Enumerable of the Operations for an openapi_document,
|
4
6
|
# and offers subscripting by operationId.
|
5
7
|
class OperationsScope
|
6
|
-
include JSI::Memoize
|
7
|
-
|
8
8
|
# @param openapi_document [Scorpio::OpenAPI::Document]
|
9
9
|
def initialize(openapi_document)
|
10
10
|
@openapi_document = openapi_document
|
11
|
+
@operations_by_id = Hash.new do |h, operationId|
|
12
|
+
op = detect { |operation| operation.operationId == operationId }
|
13
|
+
unless op
|
14
|
+
raise(::KeyError, "operationId not found: #{operationId.inspect}")
|
15
|
+
end
|
16
|
+
h[operationId] = op
|
17
|
+
end
|
11
18
|
end
|
12
19
|
attr_reader :openapi_document
|
13
20
|
|
@@ -23,17 +30,12 @@ module Scorpio
|
|
23
30
|
end
|
24
31
|
include Enumerable
|
25
32
|
|
26
|
-
#
|
27
|
-
# @
|
33
|
+
# finds an operation with the given `operationId`
|
34
|
+
# @param operationId [String] the operationId of the operation to find
|
35
|
+
# @return [Scorpio::OpenAPI::Operation]
|
28
36
|
# @raise [::KeyError] if the given operationId does not exist
|
29
37
|
def [](operationId)
|
30
|
-
|
31
|
-
detect { |operation| operation.operationId == operationId_ }.tap do |op|
|
32
|
-
unless op
|
33
|
-
raise(::KeyError, "operationId not found: #{operationId_.inspect}")
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
38
|
+
@operations_by_id[operationId]
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Scorpio
|
4
|
+
module OpenAPI
|
5
|
+
module Reference
|
6
|
+
# overrides JSI::Base#[] to implicitly dereference this Reference, except when
|
7
|
+
# the given token is present in this Reference's instance (this should usually
|
8
|
+
# only apply to the token '$ref')
|
9
|
+
def [](token, *a, &b)
|
10
|
+
if respond_to?(:to_hash) && !key?(token)
|
11
|
+
deref do |deref_jsi|
|
12
|
+
return deref_jsi[token]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
return super
|
16
|
+
end
|
17
|
+
|
18
|
+
# yields or returns the target of this reference
|
19
|
+
# @yield [JSI::Base] if a block is given
|
20
|
+
# @return [JSI::Base]
|
21
|
+
def deref
|
22
|
+
return unless respond_to?(:to_hash) && self['$ref'].respond_to?(:to_str)
|
23
|
+
|
24
|
+
ref_uri = Addressable::URI.parse(self['$ref'])
|
25
|
+
ref_uri_nofrag = ref_uri.merge(fragment: nil)
|
26
|
+
|
27
|
+
if !ref_uri_nofrag.empty? || ref_uri.fragment.nil?
|
28
|
+
raise(NotImplementedError,
|
29
|
+
"Scorpio currently only supports fragment URIs as OpenAPI references. cannot find reference by uri: #{self['$ref']}"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
ptr = JSI::Ptr.from_fragment(ref_uri.fragment)
|
34
|
+
deref_jsi = ptr.evaluate(jsi_root_node)
|
35
|
+
|
36
|
+
# TODO type check deref_jsi
|
37
|
+
|
38
|
+
yield deref_jsi if block_given?
|
39
|
+
|
40
|
+
deref_jsi
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Scorpio
|
2
|
+
module OpenAPI
|
3
|
+
module Tag
|
4
|
+
# operations in the openapi document which have a tag with this tag's name
|
5
|
+
# @return [Enumerable<Scorpio::OpenAPI::Operation>]
|
6
|
+
def operations
|
7
|
+
unless jsi_root_node.is_a?(OpenAPI::Document)
|
8
|
+
raise("Tag#operations cannot be used on a Tag that is not inside an OpenAPI document")
|
9
|
+
end
|
10
|
+
|
11
|
+
jsi_root_node.operations.select { |op| op.tags.respond_to?(:to_ary) && op.tags.include?(name) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Scorpio
|
2
4
|
module OpenAPI
|
3
5
|
module V3
|
@@ -6,7 +8,7 @@ module Scorpio
|
|
6
8
|
# An object representing a Server.
|
7
9
|
#
|
8
10
|
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#serverObject
|
9
|
-
|
11
|
+
module Server
|
10
12
|
# expands this server's #url using the given_server_variables. any variables
|
11
13
|
# that are in the url but not in the given server variables are filled in
|
12
14
|
# using the default value for the variable.
|
@@ -34,7 +36,7 @@ module Scorpio
|
|
34
36
|
server_variables = given_server_variables
|
35
37
|
end
|
36
38
|
template = Addressable::Template.new(url)
|
37
|
-
template.expand(server_variables)
|
39
|
+
template.expand(server_variables).freeze
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|