ruby-swagger 0.0.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 +7 -0
- data/lib/ruby-swagger.rb +7 -0
- data/lib/ruby-swagger/data/contact.rb +49 -0
- data/lib/ruby-swagger/data/definitions.rb +49 -0
- data/lib/ruby-swagger/data/document.rb +181 -0
- data/lib/ruby-swagger/data/example.rb +29 -0
- data/lib/ruby-swagger/data/external_documentation.rb +24 -0
- data/lib/ruby-swagger/data/header.rb +34 -0
- data/lib/ruby-swagger/data/headers.rb +48 -0
- data/lib/ruby-swagger/data/info.rb +56 -0
- data/lib/ruby-swagger/data/items.rb +45 -0
- data/lib/ruby-swagger/data/license.rb +51 -0
- data/lib/ruby-swagger/data/mime.rb +31 -0
- data/lib/ruby-swagger/data/operation.rb +82 -0
- data/lib/ruby-swagger/data/parameter.rb +88 -0
- data/lib/ruby-swagger/data/parameters.rb +53 -0
- data/lib/ruby-swagger/data/path.rb +115 -0
- data/lib/ruby-swagger/data/paths.rb +50 -0
- data/lib/ruby-swagger/data/reference.rb +30 -0
- data/lib/ruby-swagger/data/response.rb +25 -0
- data/lib/ruby-swagger/data/responses.rb +50 -0
- data/lib/ruby-swagger/data/schema.rb +68 -0
- data/lib/ruby-swagger/data/scopes.rb +44 -0
- data/lib/ruby-swagger/data/security_definitions.rb +49 -0
- data/lib/ruby-swagger/data/security_requirement.rb +35 -0
- data/lib/ruby-swagger/data/security_scheme.rb +67 -0
- data/lib/ruby-swagger/data/tag.rb +24 -0
- data/lib/ruby-swagger/data/url.rb +26 -0
- data/lib/ruby-swagger/data/xml_object.rb +15 -0
- data/lib/ruby-swagger/grape/grape.rb +2 -0
- data/lib/ruby-swagger/grape/grape_config.rb +160 -0
- data/lib/ruby-swagger/grape/grape_presenter.rb +48 -0
- data/lib/ruby-swagger/grape/grape_template.rb +67 -0
- data/lib/ruby-swagger/grape/method.rb +295 -0
- data/lib/ruby-swagger/grape/param.rb +33 -0
- data/lib/ruby-swagger/grape/route_path.rb +37 -0
- data/lib/ruby-swagger/grape/routes.rb +52 -0
- data/lib/ruby-swagger/grape/type.rb +141 -0
- data/lib/ruby-swagger/io/comparable.rb +30 -0
- data/lib/ruby-swagger/io/definitions.rb +48 -0
- data/lib/ruby-swagger/io/file_system.rb +97 -0
- data/lib/ruby-swagger/io/paths.rb +55 -0
- data/lib/ruby-swagger/io/security.rb +45 -0
- data/lib/ruby-swagger/object.rb +67 -0
- data/lib/ruby-swagger/railtie.rb +7 -0
- data/lib/ruby-swagger/template.rb +29 -0
- data/lib/tasks/swagger.rake +125 -0
- metadata +176 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
module Swagger::Data
|
4
|
+
class Url
|
5
|
+
|
6
|
+
SCHEMES = %w(http https)
|
7
|
+
|
8
|
+
attr_reader :url
|
9
|
+
|
10
|
+
def initialize(url)
|
11
|
+
@url = url
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
parsed = Addressable::URI.parse(url) or return false
|
16
|
+
SCHEMES.include?(parsed.scheme)
|
17
|
+
rescue Addressable::URI::InvalidURIError
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_swagger
|
22
|
+
url
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ruby-swagger/object'
|
2
|
+
|
3
|
+
module Swagger::Data
|
4
|
+
class XMLObject < Swagger::Object #https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#xmlObject
|
5
|
+
|
6
|
+
attr_swagger :name, :namespace, :prefix, :attribute, :wrapped
|
7
|
+
|
8
|
+
def self.parse(xml_object)
|
9
|
+
return nil unless xml_object
|
10
|
+
|
11
|
+
Swagger::Data::XMLObject.new.bulk_set(xml_object)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module Configuration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
def api_desc(description, options = {}, &block)
|
11
|
+
default_api_options!(options)
|
12
|
+
block.call if block_given?
|
13
|
+
desc description, @api_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def headers(headers_value)
|
17
|
+
raise ArgumentError.new("Grape::headers - unrecognized value #{headers_value} - allowed: Hash") unless headers_value.is_a?(Hash)
|
18
|
+
|
19
|
+
@api_options[:headers] = headers_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def api_name(name_value)
|
23
|
+
raise ArgumentError.new("Grape::api_name - unrecognized value #{name_value} - allowed: String") unless name_value.is_a?(String)
|
24
|
+
|
25
|
+
@api_options[:api_name] = name_value
|
26
|
+
end
|
27
|
+
|
28
|
+
def deprecated(deprecation_value)
|
29
|
+
raise ArgumentError.new("Grape::deprecated - unrecognized value #{deprecation_value} - allowed: true|false") unless deprecation_value == true || deprecation_value == false
|
30
|
+
|
31
|
+
@api_options[:deprecated] = deprecation_value
|
32
|
+
end
|
33
|
+
|
34
|
+
def hidden(hidden_value)
|
35
|
+
raise ArgumentError.new("Grape::hidden - unrecognized value #{hidden_value} - allowed: true|false") unless hidden_value == true || hidden_value == false
|
36
|
+
|
37
|
+
@api_options[:hidden] = hidden_value
|
38
|
+
end
|
39
|
+
|
40
|
+
def detail(detail_value)
|
41
|
+
raise ArgumentError.new("Grape::detail - unrecognized value #{detail_value} - allowed: String") unless detail_value.is_a?(String)
|
42
|
+
|
43
|
+
@api_options[:detail] = detail_value
|
44
|
+
end
|
45
|
+
|
46
|
+
def scopes(scopes_value)
|
47
|
+
return if scopes_value.nil?
|
48
|
+
|
49
|
+
if scopes_value.is_a?(Array)
|
50
|
+
scopes_value.each do |scope|
|
51
|
+
raise ArgumentError.new("Grape::scopes - unrecognized scope #{scope_value}") unless scope.is_a?(String)
|
52
|
+
end
|
53
|
+
|
54
|
+
@api_options[:scopes] = scopes_value
|
55
|
+
elsif scopes_value.is_a?(String)
|
56
|
+
@api_options[:scopes] = [scopes_value]
|
57
|
+
else
|
58
|
+
raise ArgumentError.new("Grape::scopes - unrecognized value #{scopes_value} - scopes can either be a string or an array of strings")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def tags(new_tags)
|
63
|
+
raise ArgumentError.new("Grape::tags - unrecognized value #{new_tags} - tags can only be an array of strings or a string") unless new_tags.is_a?(Array) || new_tags.is_a?(String)
|
64
|
+
|
65
|
+
if new_tags.is_a?(String)
|
66
|
+
new_tags = [new_tags]
|
67
|
+
end
|
68
|
+
|
69
|
+
@api_options[:tags]= new_tags
|
70
|
+
end
|
71
|
+
|
72
|
+
def response(new_result, options = {})
|
73
|
+
raise ArgumentError.new("Grape::response - response can't be nil") unless new_result
|
74
|
+
|
75
|
+
response_obj = {entity: new_result}
|
76
|
+
response_obj[:root] = options[:root] || options['root']
|
77
|
+
response_obj[:headers] = options[:headers] || options['headers']
|
78
|
+
response_obj[:isArray] = options[:isArray] || options['isArray']
|
79
|
+
|
80
|
+
@api_options[:response]= response_obj
|
81
|
+
end
|
82
|
+
|
83
|
+
def errors(errors_value)
|
84
|
+
raise ArgumentError.new("Grape::errors - unrecognized value #{errors_value} - errors root must be a hash of errors") unless errors_value.is_a?(Hash)
|
85
|
+
@api_options[:errors]= errors_value
|
86
|
+
end
|
87
|
+
|
88
|
+
@@headers = {}
|
89
|
+
def default_headers(new_value)
|
90
|
+
@@headers = new_value
|
91
|
+
end
|
92
|
+
|
93
|
+
@@deprecated = false
|
94
|
+
def default_deprecated(new_value)
|
95
|
+
@@deprecated = new_value
|
96
|
+
end
|
97
|
+
|
98
|
+
@@hidden = false
|
99
|
+
def default_hidden(new_value)
|
100
|
+
@@hidden = new_value
|
101
|
+
end
|
102
|
+
|
103
|
+
@@scopes = nil
|
104
|
+
def default_scopes(new_value)
|
105
|
+
@@scopes = new_value
|
106
|
+
end
|
107
|
+
|
108
|
+
@@tags = []
|
109
|
+
def default_tags(new_value)
|
110
|
+
@@tags = new_value
|
111
|
+
end
|
112
|
+
|
113
|
+
@@result = nil
|
114
|
+
def default_result(new_value)
|
115
|
+
@@result = new_value
|
116
|
+
end
|
117
|
+
|
118
|
+
@@errors = nil
|
119
|
+
def default_errors(new_value)
|
120
|
+
@@errors = new_value
|
121
|
+
end
|
122
|
+
|
123
|
+
@@response_headers = nil
|
124
|
+
def default_response_headers(new_value)
|
125
|
+
@@response_headers = new_value
|
126
|
+
end
|
127
|
+
|
128
|
+
@@response_root = nil
|
129
|
+
def default_response_root(new_value)
|
130
|
+
@@response_root = new_value
|
131
|
+
end
|
132
|
+
|
133
|
+
@@response_entity = nil
|
134
|
+
def default_response_entity(new_value)
|
135
|
+
@@response_entity = new_value
|
136
|
+
end
|
137
|
+
|
138
|
+
def default_api_options!(options)
|
139
|
+
@api_options = {
|
140
|
+
headers: @@headers,
|
141
|
+
deprecated: @@deprecated,
|
142
|
+
hidden: @@hidden,
|
143
|
+
scopes: @@scopes,
|
144
|
+
tags: @@tags,
|
145
|
+
response: {
|
146
|
+
entity: @@response_entity,
|
147
|
+
root: @@response_root,
|
148
|
+
headers: @@response_headers,
|
149
|
+
isArray: false
|
150
|
+
},
|
151
|
+
errors: @@errors,
|
152
|
+
api_name: nil,
|
153
|
+
detail: ''
|
154
|
+
}.merge(options)
|
155
|
+
@description = ''
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module InsideRoute
|
6
|
+
def api_present(*args)
|
7
|
+
|
8
|
+
args_list = args || []
|
9
|
+
options = {}
|
10
|
+
|
11
|
+
# Initialize the options hash - either by assigning to the current options for the method or with a new one
|
12
|
+
if args_list.count == 2
|
13
|
+
|
14
|
+
if args_list.last.kind_of?(Hash)
|
15
|
+
options = args_list.last
|
16
|
+
else
|
17
|
+
raise ArgumentError.new "The expected second argument for api_present is a Hash, but I got a #{args_list.last.class}"
|
18
|
+
end
|
19
|
+
|
20
|
+
elsif args_list.count == 1
|
21
|
+
|
22
|
+
#Initialize the option list
|
23
|
+
args_list << options
|
24
|
+
|
25
|
+
elsif args_list.count > 2 || args_list.count == 0
|
26
|
+
raise ArgumentError.new "Invalid number of arguments - got #{args_list.count}. expected 1 or 2 parameters"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Setting the grape :with
|
30
|
+
if route.route_response.present? && route.route_response[:entity].present? &&!options[:with].present? && route.route_response[:entity].kind_of?(Class)
|
31
|
+
options[:with] = route.route_response[:entity]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Setting the grape :root
|
35
|
+
if route.route_response.present? && route.route_response[:root].present? && !options[:root].present? && route.route_response[:root].kind_of?(String)
|
36
|
+
options[:root] = route.route_response[:root]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Setting the :current_user extension
|
40
|
+
if defined?(current_user)
|
41
|
+
options[:current_user] = current_user
|
42
|
+
end
|
43
|
+
|
44
|
+
present *args_list
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'ruby-swagger/data/document'
|
2
|
+
require 'ruby-swagger/template'
|
3
|
+
require 'ruby-swagger/data/definitions'
|
4
|
+
require 'ruby-swagger/grape/routes'
|
5
|
+
require 'ruby-swagger/grape/type'
|
6
|
+
require 'ruby-swagger/data/security_scheme'
|
7
|
+
require 'ruby-swagger/data/security_definitions'
|
8
|
+
|
9
|
+
module Swagger::Grape
|
10
|
+
class Template
|
11
|
+
|
12
|
+
def self.generate(base_class)
|
13
|
+
swagger_doc = Swagger::Template.generate
|
14
|
+
|
15
|
+
routes = Swagger::Grape::Routes.new(base_class.routes)
|
16
|
+
|
17
|
+
swagger_doc.paths = routes.to_swagger
|
18
|
+
swagger_doc.definitions = Swagger::Data::Definitions.new
|
19
|
+
|
20
|
+
extract_all_types(routes.types).sort.each do |type|
|
21
|
+
grape_type = Swagger::Grape::Type.new(type)
|
22
|
+
|
23
|
+
swagger_doc.definitions.add_definition(type.to_s, grape_type.to_swagger(false))
|
24
|
+
end
|
25
|
+
|
26
|
+
if routes.scopes.present?
|
27
|
+
scheme = Swagger::Data::SecurityScheme.new
|
28
|
+
scheme.type = 'oauth2'
|
29
|
+
scheme.flow = 'accessCode'
|
30
|
+
scheme.authorizationUrl = 'https://'
|
31
|
+
scheme.tokenUrl = 'https://'
|
32
|
+
scopes = {}
|
33
|
+
routes.scopes.uniq.each do |scope|
|
34
|
+
scopes[scope] = ""
|
35
|
+
end
|
36
|
+
scheme.scopes = scopes
|
37
|
+
|
38
|
+
swagger_doc.securityDefinitions = Swagger::Data::SecurityDefinitions.new
|
39
|
+
swagger_doc.securityDefinitions.add_param("oauth2", scheme)
|
40
|
+
end
|
41
|
+
|
42
|
+
swagger_doc
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.extract_all_types(types, all_types = [])
|
46
|
+
return all_types.uniq if types.length == 0
|
47
|
+
|
48
|
+
new_types = []
|
49
|
+
|
50
|
+
types.each do |type|
|
51
|
+
all_types << type.to_s unless all_types.include?(type.to_s)
|
52
|
+
|
53
|
+
grape_type = Swagger::Grape::Type.new(type)
|
54
|
+
|
55
|
+
grape_type.sub_types.each do |new_type|
|
56
|
+
unless all_types.include?(new_type.to_s)
|
57
|
+
new_types << new_type.to_s
|
58
|
+
all_types << new_type.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
extract_all_types(new_types, all_types)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'ruby-swagger/data/operation'
|
2
|
+
require 'ruby-swagger/grape/type'
|
3
|
+
|
4
|
+
module Swagger::Grape
|
5
|
+
class Method
|
6
|
+
|
7
|
+
attr_reader :operation, :types, :scopes
|
8
|
+
|
9
|
+
def initialize(route_name, route)
|
10
|
+
@route_name = route_name
|
11
|
+
@route = route
|
12
|
+
@types = []
|
13
|
+
@scopes = []
|
14
|
+
|
15
|
+
new_operation
|
16
|
+
operation_params
|
17
|
+
operation_responses
|
18
|
+
operation_security
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
#generate the base of the operation
|
26
|
+
def new_operation
|
27
|
+
@operation = Swagger::Data::Operation.new
|
28
|
+
@operation.tags = grape_tags
|
29
|
+
@operation.operationId = @route.route_api_name if @route.route_api_name && @route.route_api_name.length > 0
|
30
|
+
@operation.summary = @route.route_description
|
31
|
+
@operation.description = (@route.route_detail && @route.route_detail.length > 0) ? @route.route_detail : @route.route_description
|
32
|
+
@operation.deprecated = @route.route_deprecated if @route.route_deprecated #grape extension
|
33
|
+
|
34
|
+
@operation
|
35
|
+
end
|
36
|
+
|
37
|
+
#extract all the parameters from the method definition (in path, url, body)
|
38
|
+
def operation_params
|
39
|
+
extract_params_and_types
|
40
|
+
|
41
|
+
@params.each do |param_name, parameter|
|
42
|
+
operation.add_parameter(parameter)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#extract the data about the response of the method
|
47
|
+
def operation_responses
|
48
|
+
@operation.responses = Swagger::Data::Responses.new
|
49
|
+
|
50
|
+
# Include all the possible errors in the response (store the types, they are documented separately)
|
51
|
+
(@route.route_errors || {}).each do |code, response|
|
52
|
+
error_response = {'description' => response['description'] || response[:description]}
|
53
|
+
|
54
|
+
if entity = (response[:entity] || response['entity'])
|
55
|
+
type = Object.const_get entity.to_s
|
56
|
+
|
57
|
+
error_response['schema'] = {}
|
58
|
+
error_response['schema']['$ref'] = "#/definitions/#{type.to_s}"
|
59
|
+
|
60
|
+
remember_type(type)
|
61
|
+
end
|
62
|
+
|
63
|
+
@operation.responses.add_response(code, Swagger::Data::Response.parse(error_response))
|
64
|
+
end
|
65
|
+
|
66
|
+
if @route.route_response.present? && @route.route_response[:entity].present?
|
67
|
+
rainbow_response = {'description' => 'Successful result of the operation'}
|
68
|
+
|
69
|
+
type = Swagger::Grape::Type.new(@route.route_response[:entity].to_s)
|
70
|
+
current_obj = rainbow_response['schema'] = {}
|
71
|
+
remember_type(@route.route_response[:entity])
|
72
|
+
|
73
|
+
# Include any response headers in the documentation of the response
|
74
|
+
if @route.route_response[:headers].present?
|
75
|
+
@route.route_response[:headers].each do |header_key, header_value|
|
76
|
+
next unless header_value.present?
|
77
|
+
rainbow_response['headers'] ||= {}
|
78
|
+
|
79
|
+
rainbow_response['headers'][header_key] = {
|
80
|
+
'description'=> header_value['description'] || header_value[:description],
|
81
|
+
'type'=> header_value['type'] || header_value[:type],
|
82
|
+
'format'=> header_value['format'] || header_value[:format]
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if @route.route_response[:root].present?
|
88
|
+
# A case where the response contains a single key in the response
|
89
|
+
|
90
|
+
if @route.route_response[:isArray] == true
|
91
|
+
# an array that starts from a key named root
|
92
|
+
rainbow_response['schema']['type'] = 'object'
|
93
|
+
rainbow_response['schema']['properties'] = {
|
94
|
+
@route.route_response[:root] => {
|
95
|
+
'type' => 'array',
|
96
|
+
'items' => type.to_swagger
|
97
|
+
}
|
98
|
+
}
|
99
|
+
else
|
100
|
+
rainbow_response['schema']['type'] = 'object'
|
101
|
+
rainbow_response['schema']['properties'] = {
|
102
|
+
@route.route_response[:root] => type.to_swagger
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
else
|
107
|
+
|
108
|
+
if @route.route_response[:isArray] == true
|
109
|
+
rainbow_response['schema']['type'] = 'array'
|
110
|
+
rainbow_response['schema']['items'] = type.to_swagger
|
111
|
+
else
|
112
|
+
rainbow_response['schema'] = type.to_swagger
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
@operation.responses.add_response('200', Swagger::Data::Response.parse(rainbow_response))
|
118
|
+
end
|
119
|
+
|
120
|
+
@operation.responses.add_response('default', Swagger::Data::Response.parse({'description' => 'Unexpected error'}))
|
121
|
+
end
|
122
|
+
|
123
|
+
def operation_security
|
124
|
+
if @route.route_scopes #grape extensions
|
125
|
+
security = Swagger::Data::SecurityRequirement.new
|
126
|
+
security.add_requirement('oauth2', @route.route_scopes)
|
127
|
+
@operation.security = [security]
|
128
|
+
|
129
|
+
@route.route_scopes.each do |scope|
|
130
|
+
@scopes << scope unless @scopes.include?(scope)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#extract the tags
|
136
|
+
def grape_tags
|
137
|
+
(@route.route_tags && !@route.route_tags.empty?) ? @route.route_tags : [@route_name.split('/')[1]]
|
138
|
+
end
|
139
|
+
|
140
|
+
def extract_params_and_types
|
141
|
+
@params = {}
|
142
|
+
|
143
|
+
header_params
|
144
|
+
path_params
|
145
|
+
|
146
|
+
case @route.route_method.downcase
|
147
|
+
when 'get'
|
148
|
+
query_params
|
149
|
+
when 'delete'
|
150
|
+
query_params
|
151
|
+
when 'post'
|
152
|
+
body_params
|
153
|
+
when 'put'
|
154
|
+
body_params
|
155
|
+
when 'patch'
|
156
|
+
body_params
|
157
|
+
when 'head'
|
158
|
+
raise ArgumentError.new("Don't know how to handle the http verb HEAD for #{@route_name}")
|
159
|
+
else
|
160
|
+
raise ArgumentError.new("Don't know how to handle the http verb #{@route.route_method} for #{@route_name}")
|
161
|
+
end
|
162
|
+
|
163
|
+
@params
|
164
|
+
end
|
165
|
+
|
166
|
+
def header_params
|
167
|
+
@params ||= {}
|
168
|
+
|
169
|
+
#include all the parameters that are in the headers
|
170
|
+
if @route.route_headers
|
171
|
+
@route.route_headers.each do |header_key, header_value|
|
172
|
+
@params[header_key] = {'name' => header_key,
|
173
|
+
'in' => 'header',
|
174
|
+
'required' => (header_value[:required] == true),
|
175
|
+
'type' => 'string',
|
176
|
+
'description' => header_value[:description]}
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
@params
|
181
|
+
end
|
182
|
+
|
183
|
+
def path_params
|
184
|
+
#include all the parameters that are in the path
|
185
|
+
|
186
|
+
@route_name.scan(/\{[a-zA-Z0-9\-\_]+\}/).each do |parameter| #scan all parameters in the url
|
187
|
+
param_name = parameter[1..parameter.length-2]
|
188
|
+
@params[param_name] = {'name' => param_name,
|
189
|
+
'in' => 'path',
|
190
|
+
'required' => true,
|
191
|
+
'type' => 'string'}
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
def query_params
|
197
|
+
@route.route_params.each do |parameter|
|
198
|
+
next if @params[parameter.first.to_s]
|
199
|
+
|
200
|
+
swag_param = Swagger::Data::Parameter.from_grape(parameter)
|
201
|
+
next unless swag_param
|
202
|
+
|
203
|
+
swag_param.in = 'query'
|
204
|
+
|
205
|
+
@params[parameter.first.to_s] = swag_param
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def body_params
|
210
|
+
#include all the parameters that are in the content-body
|
211
|
+
return unless @route.route_params && @route.route_params.length > 0
|
212
|
+
|
213
|
+
root_param = Swagger::Data::Parameter.parse({'name' => 'body',
|
214
|
+
'in' => 'body',
|
215
|
+
'description' => 'the content of the request',
|
216
|
+
'schema' => {'type' => 'object', 'properties' => {}}})
|
217
|
+
|
218
|
+
#create the params schema
|
219
|
+
@route.route_params.each do |parameter|
|
220
|
+
param_name = parameter.first
|
221
|
+
param_value = parameter.last
|
222
|
+
schema = root_param.schema
|
223
|
+
|
224
|
+
next if @params.keys.include?(param_name)
|
225
|
+
|
226
|
+
if param_name.scan(/[0-9a-zA-Z_]+/).count == 1
|
227
|
+
#it's a simple parameter, adding it to the properties of the main object
|
228
|
+
converted_param = Swagger::Grape::Param.new(param_value)
|
229
|
+
schema.properties[param_name] = converted_param.to_swagger
|
230
|
+
required_parameter(schema, param_name, param_value)
|
231
|
+
remember_type(converted_param.type_definition) if converted_param.has_type_definition?
|
232
|
+
else
|
233
|
+
schema_with_subobjects(schema, param_name, parameter.last)
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
schema= root_param.schema
|
239
|
+
@params['body'] = root_param if !schema.properties.nil? && schema.properties.keys.length > 0
|
240
|
+
end
|
241
|
+
|
242
|
+
def required_parameter(schema, name, parameter)
|
243
|
+
return if parameter.nil? || parameter[:required].nil? || parameter[:required] == false
|
244
|
+
|
245
|
+
schema['required'] ||= []
|
246
|
+
schema['required'] << name
|
247
|
+
end
|
248
|
+
|
249
|
+
def schema_with_subobjects(schema, param_name, parameter)
|
250
|
+
path = param_name.scan(/[0-9a-zA-Z_]+/)
|
251
|
+
append_to = find_elem_in_schema(schema, path.dup)
|
252
|
+
converted_param = Swagger::Grape::Param.new(parameter)
|
253
|
+
append_to['properties'][path.last] = converted_param.to_swagger
|
254
|
+
|
255
|
+
remember_type(converted_param.type_definition) if converted_param.has_type_definition?
|
256
|
+
|
257
|
+
required_parameter(append_to, path.last, parameter)
|
258
|
+
end
|
259
|
+
|
260
|
+
def find_elem_in_schema(root, schema_path)
|
261
|
+
return root if schema_path.nil? || schema_path.empty?
|
262
|
+
|
263
|
+
next_elem = schema_path.shift
|
264
|
+
|
265
|
+
return root if root['properties'][next_elem].nil?
|
266
|
+
|
267
|
+
case root['properties'][next_elem]['type']
|
268
|
+
when 'array'
|
269
|
+
#to descend an array this must be an array of objects
|
270
|
+
root['properties'][next_elem]['items']['type'] = 'object'
|
271
|
+
root['properties'][next_elem]['items']['properties'] ||= {}
|
272
|
+
|
273
|
+
find_elem_in_schema(root['properties'][next_elem]['items'], schema_path)
|
274
|
+
when 'object'
|
275
|
+
find_elem_in_schema(root['properties'][next_elem], schema_path)
|
276
|
+
else
|
277
|
+
raise ArgumentError.new("Don't know how to handle the schema path #{schema_path.join('/')}")
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
# Store an object "type" seen on parameters or response types
|
283
|
+
def remember_type(type)
|
284
|
+
@types ||= []
|
285
|
+
|
286
|
+
return if %w(string integer boolean float array symbol virtus::attribute::boolean rack::multipart::uploadedfile date datetime).include?(type.to_s.downcase)
|
287
|
+
|
288
|
+
type = Object.const_get type.to_s
|
289
|
+
return if @types.include?(type.to_s)
|
290
|
+
|
291
|
+
@types << type.to_s
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
end
|