scorpio 0.0.4 → 0.1.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 +8 -0
- data/README.md +37 -14
- data/bin/documents_to_yml.rb +26 -0
- data/documents/swagger.io/v2/schema.json +1607 -0
- data/documents/swagger.io/v2/schema.yml +1079 -0
- data/documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest +684 -0
- data/{getRest.yml → documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest.yml} +34 -72
- data/lib/scorpio.rb +30 -1
- data/lib/scorpio/google_api_document.rb +232 -0
- data/lib/scorpio/json-schema-fragments.rb +191 -0
- data/lib/scorpio/json.rb +5 -0
- data/lib/scorpio/json/node.rb +214 -0
- data/lib/scorpio/model.rb +178 -91
- data/lib/scorpio/openapi.rb +81 -0
- data/lib/scorpio/schema.rb +133 -0
- data/lib/scorpio/schema_object_base.rb +227 -0
- data/lib/scorpio/typelike_modules.rb +52 -0
- data/lib/scorpio/version.rb +1 -1
- data/scorpio.gemspec +2 -1
- metadata +20 -8
@@ -1,13 +1,12 @@
|
|
1
|
-
|
1
|
+
---
|
2
2
|
kind: discovery#restDescription
|
3
|
-
etag: '"
|
3
|
+
etag: '"YWOzh2SDasdU84ArJnpYek-OMdg/K3nEDF6hixE8Pks2-9Ysn9j9prQ"'
|
4
4
|
discoveryVersion: v1
|
5
5
|
id: discovery:v1
|
6
6
|
name: discovery
|
7
7
|
version: v1
|
8
8
|
title: APIs Discovery Service
|
9
|
-
description: Provides information about other Google APIs, such as what APIs are available,
|
10
|
-
the resource, and method details for each API.
|
9
|
+
description: Provides information about other Google APIs, such as what APIs are available, the resource, and method details for each API.
|
11
10
|
ownerDomain: google.com
|
12
11
|
ownerName: Google
|
13
12
|
icons:
|
@@ -19,7 +18,7 @@ baseUrl: https://www.googleapis.com/discovery/v1/
|
|
19
18
|
basePath: "/discovery/v1/"
|
20
19
|
rootUrl: https://www.googleapis.com/
|
21
20
|
servicePath: discovery/v1/
|
22
|
-
batchPath: batch
|
21
|
+
batchPath: batch/discovery/v1
|
23
22
|
parameters:
|
24
23
|
alt:
|
25
24
|
type: string
|
@@ -36,8 +35,7 @@ parameters:
|
|
36
35
|
location: query
|
37
36
|
key:
|
38
37
|
type: string
|
39
|
-
description: API key. Your API key identifies your project and provides you with
|
40
|
-
API access, quota, and reports. Required unless you provide an OAuth 2.0 token.
|
38
|
+
description: API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.
|
41
39
|
location: query
|
42
40
|
oauth_token:
|
43
41
|
type: string
|
@@ -50,14 +48,11 @@ parameters:
|
|
50
48
|
location: query
|
51
49
|
quotaUser:
|
52
50
|
type: string
|
53
|
-
description: Available to use for quota purposes for server-side applications.
|
54
|
-
Can be any arbitrary string assigned to a user, but should not exceed 40 characters.
|
55
|
-
Overrides userIp if both are provided.
|
51
|
+
description: Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.
|
56
52
|
location: query
|
57
53
|
userIp:
|
58
54
|
type: string
|
59
|
-
description: IP address of the site where the request originates. Use this if
|
60
|
-
you want to enforce per-user limits.
|
55
|
+
description: IP address of the site where the request originates. Use this if you want to enforce per-user limits.
|
61
56
|
location: query
|
62
57
|
schemas:
|
63
58
|
DirectoryList:
|
@@ -66,8 +61,7 @@ schemas:
|
|
66
61
|
properties:
|
67
62
|
discoveryVersion:
|
68
63
|
type: string
|
69
|
-
description: Indicate the version of the Discovery API used to generate this
|
70
|
-
doc.
|
64
|
+
description: Indicate the version of the Discovery API used to generate this doc.
|
71
65
|
default: v1
|
72
66
|
items:
|
73
67
|
type: array
|
@@ -131,20 +125,17 @@ schemas:
|
|
131
125
|
properties:
|
132
126
|
"$ref":
|
133
127
|
type: string
|
134
|
-
description: A reference to another schema. The value of this property is
|
135
|
-
the "id" of another schema.
|
128
|
+
description: A reference to another schema. The value of this property is the "id" of another schema.
|
136
129
|
additionalProperties:
|
137
130
|
"$ref": JsonSchema
|
138
|
-
description: If this is a schema for an object, this property is the schema
|
139
|
-
for any additional properties with dynamic keys on this object.
|
131
|
+
description: If this is a schema for an object, this property is the schema for any additional properties with dynamic keys on this object.
|
140
132
|
annotations:
|
141
133
|
type: object
|
142
134
|
description: Additional information about this property.
|
143
135
|
properties:
|
144
136
|
required:
|
145
137
|
type: array
|
146
|
-
description: A list of methods for which this property is required on
|
147
|
-
requests.
|
138
|
+
description: A list of methods for which this property is required on requests.
|
148
139
|
items:
|
149
140
|
type: string
|
150
141
|
default:
|
@@ -160,25 +151,21 @@ schemas:
|
|
160
151
|
type: string
|
161
152
|
enumDescriptions:
|
162
153
|
type: array
|
163
|
-
description: The descriptions for the enums. Each position maps to the corresponding
|
164
|
-
value in the "enum" array.
|
154
|
+
description: The descriptions for the enums. Each position maps to the corresponding value in the "enum" array.
|
165
155
|
items:
|
166
156
|
type: string
|
167
157
|
format:
|
168
158
|
type: string
|
169
|
-
description: 'An additional regular expression or key that helps constrain
|
170
|
-
the value. For more details see: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23'
|
159
|
+
description: 'An additional regular expression or key that helps constrain the value. For more details see: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23'
|
171
160
|
id:
|
172
161
|
type: string
|
173
162
|
description: Unique identifier for this schema.
|
174
163
|
items:
|
175
164
|
"$ref": JsonSchema
|
176
|
-
description: If this is a schema for an array, this property is the schema
|
177
|
-
for each element in the array.
|
165
|
+
description: If this is a schema for an array, this property is the schema for each element in the array.
|
178
166
|
location:
|
179
167
|
type: string
|
180
|
-
description: Whether this parameter goes in the query or the path for REST
|
181
|
-
requests.
|
168
|
+
description: Whether this parameter goes in the query or the path for REST requests.
|
182
169
|
maximum:
|
183
170
|
type: string
|
184
171
|
description: The maximum value of this parameter.
|
@@ -187,21 +174,16 @@ schemas:
|
|
187
174
|
description: The minimum value of this parameter.
|
188
175
|
pattern:
|
189
176
|
type: string
|
190
|
-
description: 'The regular expression this parameter must conform to. Uses
|
191
|
-
Java 6 regex format: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html'
|
177
|
+
description: 'The regular expression this parameter must conform to. Uses Java 6 regex format: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html'
|
192
178
|
properties:
|
193
179
|
type: object
|
194
|
-
description: If this is a schema for an object, list the schema for each property
|
195
|
-
of this object.
|
180
|
+
description: If this is a schema for an object, list the schema for each property of this object.
|
196
181
|
additionalProperties:
|
197
182
|
"$ref": JsonSchema
|
198
|
-
description: A single property of this object. The value is itself a JSON
|
199
|
-
Schema object describing this property.
|
183
|
+
description: A single property of this object. The value is itself a JSON Schema object describing this property.
|
200
184
|
readOnly:
|
201
185
|
type: boolean
|
202
|
-
description: The value is read-only, generated by the service. The value cannot
|
203
|
-
be modified by the client. If the value is included in a POST, PUT, or PATCH
|
204
|
-
request, it is ignored by the service.
|
186
|
+
description: The value is read-only, generated by the service. The value cannot be modified by the client. If the value is included in a POST, PUT, or PATCH request, it is ignored by the service.
|
205
187
|
repeated:
|
206
188
|
type: boolean
|
207
189
|
description: Whether this parameter may appear multiple times.
|
@@ -210,13 +192,10 @@ schemas:
|
|
210
192
|
description: Whether the parameter is required.
|
211
193
|
type:
|
212
194
|
type: string
|
213
|
-
description: 'The value type for this schema. A list of values can be found
|
214
|
-
here: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1'
|
195
|
+
description: 'The value type for this schema. A list of values can be found here: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1'
|
215
196
|
variant:
|
216
197
|
type: object
|
217
|
-
description: In a variant data type, the value of one property is used to
|
218
|
-
determine how to interpret the entire entity. Its value must exist in a
|
219
|
-
map of descriminant values to schema names.
|
198
|
+
description: In a variant data type, the value of one property is used to determine how to interpret the entire entity. Its value must exist in a map of descriminant values to schema names.
|
220
199
|
properties:
|
221
200
|
discriminant:
|
222
201
|
type: string
|
@@ -262,18 +241,15 @@ schemas:
|
|
262
241
|
batchPath:
|
263
242
|
type: string
|
264
243
|
description: The path for REST batch requests.
|
265
|
-
default: batch
|
266
244
|
canonicalName:
|
267
245
|
type: string
|
268
|
-
description: Indicates how the API name should be capitalized and split into
|
269
|
-
various parts. Useful for generating pretty class names.
|
246
|
+
description: Indicates how the API name should be capitalized and split into various parts. Useful for generating pretty class names.
|
270
247
|
description:
|
271
248
|
type: string
|
272
249
|
description: The description of this API.
|
273
250
|
discoveryVersion:
|
274
251
|
type: string
|
275
|
-
description: Indicate the version of the Discovery API used to generate this
|
276
|
-
doc.
|
252
|
+
description: Indicate the version of the Discovery API used to generate this doc.
|
277
253
|
default: v1
|
278
254
|
documentationLink:
|
279
255
|
type: string
|
@@ -284,8 +260,7 @@ schemas:
|
|
284
260
|
readOnly: true
|
285
261
|
exponentialBackoffDefault:
|
286
262
|
type: boolean
|
287
|
-
description: Enable exponential backoff for suitable methods in the generated
|
288
|
-
clients.
|
263
|
+
description: Enable exponential backoff for suitable methods in the generated clients.
|
289
264
|
features:
|
290
265
|
type: array
|
291
266
|
description: A list of supported features for this API.
|
@@ -324,9 +299,7 @@ schemas:
|
|
324
299
|
description: The name of this API.
|
325
300
|
ownerDomain:
|
326
301
|
type: string
|
327
|
-
description: The domain of the owner of this API. Together with the ownerName
|
328
|
-
and a packagePath values, this can be used to generate a library for this
|
329
|
-
API which would have a unique fully qualified name.
|
302
|
+
description: The domain of the owner of this API. Together with the ownerName and a packagePath values, this can be used to generate a library for this API which would have a unique fully qualified name.
|
330
303
|
ownerName:
|
331
304
|
type: string
|
332
305
|
description: The name of the owner of this API. See ownerDomain.
|
@@ -348,8 +321,7 @@ schemas:
|
|
348
321
|
description: The resources in this API.
|
349
322
|
additionalProperties:
|
350
323
|
"$ref": RestResource
|
351
|
-
description: An individual resource description. Contains methods and sub-resources
|
352
|
-
related to this resource.
|
324
|
+
description: An individual resource description. Contains methods and sub-resources related to this resource.
|
353
325
|
revision:
|
354
326
|
type: string
|
355
327
|
description: The version of this API.
|
@@ -382,15 +354,13 @@ schemas:
|
|
382
354
|
description: Description of this method.
|
383
355
|
etagRequired:
|
384
356
|
type: boolean
|
385
|
-
description: Whether this method requires an ETag to be specified. The ETag
|
386
|
-
is sent as an HTTP If-Match or If-None-Match header.
|
357
|
+
description: Whether this method requires an ETag to be specified. The ETag is sent as an HTTP If-Match or If-None-Match header.
|
387
358
|
httpMethod:
|
388
359
|
type: string
|
389
360
|
description: HTTP method used by this method.
|
390
361
|
id:
|
391
362
|
type: string
|
392
|
-
description: A unique ID for this method. This property can be used to match
|
393
|
-
methods between different versions of Discovery.
|
363
|
+
description: A unique ID for this method. This property can be used to match methods between different versions of Discovery.
|
394
364
|
mediaUpload:
|
395
365
|
type: object
|
396
366
|
description: Media upload parameters.
|
@@ -413,13 +383,11 @@ schemas:
|
|
413
383
|
properties:
|
414
384
|
multipart:
|
415
385
|
type: boolean
|
416
|
-
description: True if this endpoint supports uploading multipart
|
417
|
-
media.
|
386
|
+
description: True if this endpoint supports uploading multipart media.
|
418
387
|
default: 'true'
|
419
388
|
path:
|
420
389
|
type: string
|
421
|
-
description: The URI path to be used for upload. Should be used
|
422
|
-
in conjunction with the basePath property at the api-level.
|
390
|
+
description: The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level.
|
423
391
|
simple:
|
424
392
|
type: object
|
425
393
|
description: Supports uploading as a single HTTP request.
|
@@ -430,13 +398,10 @@ schemas:
|
|
430
398
|
default: 'true'
|
431
399
|
path:
|
432
400
|
type: string
|
433
|
-
description: The URI path to be used for upload. Should be used
|
434
|
-
in conjunction with the basePath property at the api-level.
|
401
|
+
description: The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level.
|
435
402
|
parameterOrder:
|
436
403
|
type: array
|
437
|
-
description: Ordered list of required parameters, serves as a hint to clients
|
438
|
-
on how to structure their method signatures. The array is ordered such that
|
439
|
-
the "most-significant" parameter appears first.
|
404
|
+
description: Ordered list of required parameters, serves as a hint to clients on how to structure their method signatures. The array is ordered such that the "most-significant" parameter appears first.
|
440
405
|
items:
|
441
406
|
type: string
|
442
407
|
parameters:
|
@@ -447,8 +412,7 @@ schemas:
|
|
447
412
|
description: Details for a single parameter in this method.
|
448
413
|
path:
|
449
414
|
type: string
|
450
|
-
description: The URI path of this REST method. Should be used in conjunction
|
451
|
-
with the basePath property at the api-level.
|
415
|
+
description: The URI path of this REST method. Should be used in conjunction with the basePath property at the api-level.
|
452
416
|
request:
|
453
417
|
type: object
|
454
418
|
description: The schema for the request.
|
@@ -482,9 +446,7 @@ schemas:
|
|
482
446
|
description: Whether this method supports subscriptions.
|
483
447
|
useMediaDownloadService:
|
484
448
|
type: boolean
|
485
|
-
description: Indicates that downloads from this method should use the download
|
486
|
-
service URL (i.e. "/download"). Only applies if the method supports media
|
487
|
-
download.
|
449
|
+
description: Indicates that downloads from this method should use the download service URL (i.e. "/download"). Only applies if the method supports media download.
|
488
450
|
RestResource:
|
489
451
|
id: RestResource
|
490
452
|
type: object
|
data/lib/scorpio.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
require "scorpio/version"
|
2
|
+
require "pathname"
|
3
|
+
require "pp"
|
4
|
+
require "api_hammer/ycomb"
|
5
|
+
require "scorpio/json-schema-fragments"
|
2
6
|
|
3
7
|
module Scorpio
|
8
|
+
def self.root
|
9
|
+
@root ||= Pathname.new(__FILE__).dirname.parent.expand_path
|
10
|
+
end
|
11
|
+
|
12
|
+
# generally put in code paths that are not expected to be valid control flow paths.
|
13
|
+
# rather a NotImplementedCorrectlyError. but that's too long.
|
14
|
+
class Bug < NotImplementedError
|
15
|
+
end
|
16
|
+
|
4
17
|
proc { |v| define_singleton_method(:error_classes_by_status) { v } }.call({})
|
5
18
|
class Error < StandardError; end
|
6
19
|
class HTTPError < Error
|
@@ -53,13 +66,29 @@ module Scorpio
|
|
53
66
|
error_classes_by_status.freeze
|
54
67
|
|
55
68
|
autoload :Model, 'scorpio/model'
|
69
|
+
autoload :OpenAPI, 'scorpio/openapi'
|
70
|
+
autoload :Google, 'scorpio/google_api_document'
|
71
|
+
autoload :JSON, 'scorpio/json'
|
72
|
+
autoload :Schema, 'scorpio/schema'
|
56
73
|
|
57
74
|
class << self
|
58
75
|
def stringify_symbol_keys(hash)
|
59
76
|
unless hash.is_a?(Hash)
|
60
|
-
raise ArgumentError, "expected argument to be a Hash; got #{hash.class}: #{hash.
|
77
|
+
raise ArgumentError, "expected argument to be a Hash; got #{hash.class}: #{hash.pretty_inspect}"
|
61
78
|
end
|
62
79
|
hash.map { |k,v| {k.is_a?(Symbol) ? k.to_s : k => v} }.inject({}, &:update)
|
63
80
|
end
|
64
81
|
end
|
82
|
+
|
83
|
+
module FingerprintHash
|
84
|
+
def ==(other)
|
85
|
+
other.respond_to?(:fingerprint) && other.fingerprint == self.fingerprint
|
86
|
+
end
|
87
|
+
|
88
|
+
alias eql? ==
|
89
|
+
|
90
|
+
def hash
|
91
|
+
fingerprint.hash
|
92
|
+
end
|
93
|
+
end
|
65
94
|
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'api_hammer/ycomb'
|
2
|
+
require 'scorpio/schema_object_base'
|
3
|
+
|
4
|
+
module Scorpio
|
5
|
+
module Google
|
6
|
+
apidoc_schema_doc = ::JSON.parse(Scorpio.root.join('documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest').read)
|
7
|
+
api_document_class = proc do |*key|
|
8
|
+
Scorpio.class_for_schema(Scorpio::JSON::Node.new_by_type(apidoc_schema_doc, ['schemas', *key]))
|
9
|
+
end
|
10
|
+
|
11
|
+
# naming these is not strictly necessary, but is nice to have.
|
12
|
+
# generated: puts Scorpio::Google::ApiDocument.document['schemas'].select { |k,v| v['type'] == 'object' }.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = api_document_class.call('#{k}')" }
|
13
|
+
DirectoryList = api_document_class.call('DirectoryList')
|
14
|
+
JsonSchema = api_document_class.call('JsonSchema')
|
15
|
+
RestDescription = api_document_class.call('RestDescription')
|
16
|
+
RestMethod = api_document_class.call('RestMethod')
|
17
|
+
RestResource = api_document_class.call('RestResource')
|
18
|
+
|
19
|
+
# not generated
|
20
|
+
RestMethodRequest = api_document_class.call('RestMethod', 'properties', 'request')
|
21
|
+
RestMethodResponse = api_document_class.call('RestMethod', 'properties', 'response')
|
22
|
+
|
23
|
+
# google does a weird thing where it defines a schema with a $ref property where a json-schema is to be used in the document (method request and response fields), instead of just setting the schema to be the json-schema schema. we'll share a module across those schema classes that really represent schemas. is this confusingly meta enough?
|
24
|
+
module SchemaLike
|
25
|
+
def to_openapi
|
26
|
+
dup_doc = ::JSON.parse(::JSON.generate(object.content))
|
27
|
+
# openapi does not want an id field on schemas
|
28
|
+
dup_doc.delete('id')
|
29
|
+
if dup_doc['properties'].is_a?(Hash)
|
30
|
+
required_properties = dup_doc['properties'].select do |key, value|
|
31
|
+
value.is_a?(Hash) ? value.delete('required') : nil
|
32
|
+
end.keys
|
33
|
+
# put required before properties
|
34
|
+
unless required_properties.empty?
|
35
|
+
dup_doc = dup_doc.map do |k, v|
|
36
|
+
base = k == 'properties' ? {'required' => required_properties } : {}
|
37
|
+
base.merge({k => v})
|
38
|
+
end.inject({}, &:update)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
dup_doc
|
42
|
+
end
|
43
|
+
end
|
44
|
+
[JsonSchema, RestMethodRequest, RestMethodResponse].each { |klass| klass.send(:include, SchemaLike) }
|
45
|
+
|
46
|
+
class RestDescription
|
47
|
+
def to_openapi_document(options = {})
|
48
|
+
Scorpio::OpenAPI::Document.new(to_openapi_hash(options))
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_openapi_hash(options = {})
|
52
|
+
# we will be modifying the api document (RestDescription). clone self and modify that one.
|
53
|
+
ad = self.class.new(::JSON.parse(::JSON.generate(object.document)))
|
54
|
+
ad_methods = []
|
55
|
+
if ad['methods']
|
56
|
+
ad_methods += ad['methods'].map do |mn, m|
|
57
|
+
m.tap do
|
58
|
+
m.send(:define_singleton_method, :resource_name) { }
|
59
|
+
m.send(:define_singleton_method, :method_name) { mn }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
ad_methods += ad.resources.map do |rn, r|
|
64
|
+
(r['methods'] || {}).map do |mn, m|
|
65
|
+
m.tap do
|
66
|
+
m.send(:define_singleton_method, :resource_name) { rn }
|
67
|
+
m.send(:define_singleton_method, :method_name) { mn }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end.inject([], &:+)
|
71
|
+
|
72
|
+
paths = ad_methods.group_by { |m| m['path'] }.map do |path, path_methods|
|
73
|
+
unless path =~ %r(\A/)
|
74
|
+
path = '/' + path
|
75
|
+
end
|
76
|
+
operations = path_methods.group_by { |m| m['httpMethod'] }.map do |http_method, http_method_methods|
|
77
|
+
if http_method_methods.size > 1
|
78
|
+
#raise("http method #{http_method} at path #{path} not unique: #{http_method_methods.pretty_inspect}")
|
79
|
+
end
|
80
|
+
method = http_method_methods.first
|
81
|
+
unused_path_params = Addressable::Template.new(path).variables
|
82
|
+
{http_method.downcase => {}.tap do |operation|
|
83
|
+
#operation['tags'] = []
|
84
|
+
#operation['summary'] =
|
85
|
+
operation['description'] = method['description'] if method['description']
|
86
|
+
if method.resource_name && options[:x]
|
87
|
+
operation['x-resource'] = method.resource_name
|
88
|
+
operation['x-resource-method'] = method.method_name
|
89
|
+
end
|
90
|
+
#operation['externalDocs'] =
|
91
|
+
operation['operationId'] = method['id'] || (method.resource_name ? "#{method.resource_name}.#{method.method_name}" : method.method_name)
|
92
|
+
#operation['produces'] =
|
93
|
+
#operation['consumes'] =
|
94
|
+
if method['parameters']
|
95
|
+
operation['parameters'] = method['parameters'].map do |name, parameter|
|
96
|
+
{}.tap do |op_param|
|
97
|
+
op_param['description'] = parameter.description if parameter.description
|
98
|
+
op_param['name'] = name
|
99
|
+
op_param['in'] = if parameter.location
|
100
|
+
parameter.location
|
101
|
+
elsif unused_path_params.include?(name)
|
102
|
+
'path'
|
103
|
+
else
|
104
|
+
'query'
|
105
|
+
# unused: header, formdata, body
|
106
|
+
end
|
107
|
+
unused_path_params.delete(name) if op_param['in'] == 'path'
|
108
|
+
op_param['required'] = parameter.key?('required') ? parameter['required'] : op_param['in'] == 'path' ? true : false
|
109
|
+
op_param['type'] = parameter.type || 'string'
|
110
|
+
op_param['format'] = parameter.format if parameter.format
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
if unused_path_params.any?
|
115
|
+
operation['parameters'] ||= []
|
116
|
+
operation['parameters'] += unused_path_params.map do |param_name|
|
117
|
+
{
|
118
|
+
'name' => param_name,
|
119
|
+
'in' => 'path',
|
120
|
+
'required' => true,
|
121
|
+
'type' => 'string',
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
if method['request']
|
126
|
+
operation['parameters'] ||= []
|
127
|
+
operation['parameters'] << {
|
128
|
+
'name' => 'body',
|
129
|
+
'in' => 'body',
|
130
|
+
'required' => true,
|
131
|
+
'schema' => method['request'],
|
132
|
+
}
|
133
|
+
end
|
134
|
+
if method['response']
|
135
|
+
operation['responses'] = {
|
136
|
+
'default' => {
|
137
|
+
'description' => 'default response',
|
138
|
+
'schema' => method['response'],
|
139
|
+
},
|
140
|
+
}
|
141
|
+
end
|
142
|
+
end}
|
143
|
+
end.inject({}, &:update)
|
144
|
+
|
145
|
+
{path => operations}
|
146
|
+
end.inject({}, &:update)
|
147
|
+
|
148
|
+
openapi = {
|
149
|
+
'swagger' => '2.0',
|
150
|
+
'info' => { #/definitions/info
|
151
|
+
'title' => ad.title || ad.name,
|
152
|
+
'description' => ad.description,
|
153
|
+
'version' => ad.version || '',
|
154
|
+
#'termsOfService' => '',
|
155
|
+
'contact' => {
|
156
|
+
'name' => ad.ownerName,
|
157
|
+
#'url' =>
|
158
|
+
#'email' => '',
|
159
|
+
}.reject { |_, v| v.nil? },
|
160
|
+
#'license' => {
|
161
|
+
#'name' => '',
|
162
|
+
#'url' => '',
|
163
|
+
#},
|
164
|
+
},
|
165
|
+
'host' => ad.rootUrl ? Addressable::URI.parse(ad.rootUrl).host : ad.baseUrl ? Addressable::URI.parse(ad.rootUrl).host : ad.name, # uhh ... got nothin' better
|
166
|
+
'basePath' => begin
|
167
|
+
path = ad.servicePath || ad.basePath || (ad.baseUrl ? Addressable::URI.parse(ad.baseUrl).path : '/')
|
168
|
+
path =~ %r(\A/) ? path : "/" + path
|
169
|
+
end,
|
170
|
+
'schemes' => ad.rootUrl ? [Addressable::URI.parse(ad.rootUrl).scheme] : ad.baseUrl ? [Addressable::URI.parse(ad.rootUrl).scheme] : [], #/definitions/schemesList
|
171
|
+
'consumes' => ['application/json'], # we'll just make this assumption
|
172
|
+
'produces' => ['application/json'],
|
173
|
+
'paths' => paths, #/definitions/paths
|
174
|
+
}
|
175
|
+
if ad.schemas
|
176
|
+
openapi['definitions'] = ad.schemas
|
177
|
+
ad.schemas.each do |name, schema|
|
178
|
+
openapi = ycomb do |rec|
|
179
|
+
proc do |object|
|
180
|
+
if object.respond_to?(:to_hash)
|
181
|
+
object.merge(object.map do |k, v|
|
182
|
+
if k == '$ref' && (v == schema['id'] || v == "#/schemas/#{name}" || v == name)
|
183
|
+
{k => "#/definitions/#{name}"}
|
184
|
+
else
|
185
|
+
ycomb do |toopenapirec|
|
186
|
+
proc do |toopenapiobject|
|
187
|
+
toopenapiobject = toopenapiobject.to_openapi if toopenapiobject.respond_to?(:to_openapi)
|
188
|
+
if toopenapiobject.respond_to?(:to_hash)
|
189
|
+
toopenapiobject.map { |k, v| {toopenapirec.call(k) => toopenapirec.call(v)} }.inject({}, &:update)
|
190
|
+
elsif toopenapiobject.respond_to?(:to_ary)
|
191
|
+
toopenapiobject.map(&toopenapirec)
|
192
|
+
elsif toopenapiobject.is_a?(Symbol)
|
193
|
+
toopenapiobject.to_s
|
194
|
+
elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| toopenapiobject.is_a?(c) }
|
195
|
+
toopenapiobject
|
196
|
+
else
|
197
|
+
raise(TypeError, "bad (not jsonifiable) object: #{toopenapiobject.pretty_inspect}")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end.call({k => rec.call(v)})
|
201
|
+
end
|
202
|
+
end.inject({}, &:merge))
|
203
|
+
elsif object.respond_to?(:to_ary)
|
204
|
+
object.map(&rec)
|
205
|
+
else
|
206
|
+
object
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end.call(openapi)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
# check we haven't got anything that shouldn't go in a openapi document
|
213
|
+
openapi = ycomb do |rec|
|
214
|
+
proc do |object|
|
215
|
+
object = object.to_openapi if object.respond_to?(:to_openapi)
|
216
|
+
if object.respond_to?(:to_hash)
|
217
|
+
object.map { |k, v| {rec.call(k) => rec.call(v)} }.inject({}, &:update)
|
218
|
+
elsif object.respond_to?(:to_ary)
|
219
|
+
object.map(&rec)
|
220
|
+
elsif object.is_a?(Symbol)
|
221
|
+
object.to_s
|
222
|
+
elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| object.is_a?(c) }
|
223
|
+
object
|
224
|
+
else
|
225
|
+
raise(TypeError, "bad (not jsonifiable) object: #{object.pretty_inspect}")
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end.call(openapi)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|