sinatra-swagger-exposer 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-endpoint-parameter.rb +118 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-endpoint-response.rb +64 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-endpoint.rb +88 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-info.rb +72 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-parameter-validation-helper.rb +106 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-type-property.rb +82 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-type.rb +127 -0
- data/lib/sinatra/swagger-exposer/configuration/swagger-types.rb +51 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-array-value-preprocessor.rb +46 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-base-value-preprocessor.rb +48 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-parameter-preprocessor.rb +47 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-preprocessor-dispatcher.rb +45 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-primitive-value-preprocessor.rb +165 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-request-preprocessor.rb +64 -0
- data/lib/sinatra/swagger-exposer/processing/swagger-type-value-preprocessor.rb +37 -0
- data/lib/sinatra/swagger-exposer/swagger-content-creator.rb +3 -2
- data/lib/sinatra/swagger-exposer/swagger-exposer.rb +18 -20
- data/lib/sinatra/swagger-exposer/swagger-parameter-helper.rb +1 -1
- data/lib/sinatra/swagger-exposer/swagger-preprocessor-creator.rb +137 -0
- data/lib/sinatra/swagger-exposer/swagger-utilities.rb +1 -1
- data/lib/sinatra/swagger-exposer/version.rb +1 -1
- metadata +18 -10
- data/lib/sinatra/swagger-exposer/swagger-endpoint-parameter.rb +0 -197
- data/lib/sinatra/swagger-exposer/swagger-endpoint-response.rb +0 -63
- data/lib/sinatra/swagger-exposer/swagger-endpoint.rb +0 -94
- data/lib/sinatra/swagger-exposer/swagger-info.rb +0 -70
- data/lib/sinatra/swagger-exposer/swagger-parameter-preprocessor.rb +0 -187
- data/lib/sinatra/swagger-exposer/swagger-request-preprocessor.rb +0 -56
- data/lib/sinatra/swagger-exposer/swagger-type-property.rb +0 -72
- data/lib/sinatra/swagger-exposer/swagger-type.rb +0 -125
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'date'
|
2
|
-
|
3
|
-
require_relative 'swagger-endpoint-parameter'
|
4
|
-
require_relative 'swagger-parameter-helper'
|
5
|
-
require_relative 'swagger-invalid-exception'
|
6
|
-
|
7
|
-
module Sinatra
|
8
|
-
|
9
|
-
module SwaggerExposer
|
10
|
-
|
11
|
-
# Process the parameters for validation and enrichment
|
12
|
-
class SwaggerParameterPreprocessor
|
13
|
-
|
14
|
-
include SwaggerParameterHelper
|
15
|
-
|
16
|
-
def initialize(name, how_to_pass, required, type, default, params)
|
17
|
-
@name = name.to_s
|
18
|
-
@how_to_pass = how_to_pass
|
19
|
-
@required = required
|
20
|
-
@type = type
|
21
|
-
@default = default
|
22
|
-
@params = params
|
23
|
-
|
24
|
-
# All headers are upcased
|
25
|
-
if how_to_pass == HOW_TO_PASS_HEADER
|
26
|
-
@name.upcase!
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def useful?
|
31
|
-
@required ||
|
32
|
-
(!@default.nil?) ||
|
33
|
-
[TYPE_NUMBER, TYPE_INTEGER, TYPE_BOOLEAN, TYPE_DATE_TIME].include?(@type) || # Must check type
|
34
|
-
(@params.key? PARAMS_MIN_LENGTH) || (@params.key? PARAMS_MAX_LENGTH) # Must check string
|
35
|
-
end
|
36
|
-
|
37
|
-
def run(app, parsed_body)
|
38
|
-
case @how_to_pass
|
39
|
-
when HOW_TO_PASS_PATH
|
40
|
-
# can't validate
|
41
|
-
when HOW_TO_PASS_QUERY
|
42
|
-
check_param(app.params)
|
43
|
-
when HOW_TO_PASS_HEADER
|
44
|
-
check_param(app.headers)
|
45
|
-
when HOW_TO_PASS_BODY
|
46
|
-
check_param(parsed_body || {})
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def check_param(params)
|
51
|
-
if params.key?(@name)
|
52
|
-
params[@name] = validate_param_value(params[@name])
|
53
|
-
elsif @required
|
54
|
-
raise SwaggerInvalidException.new("Mandatory parameter [#{@name}] is missing")
|
55
|
-
elsif @default
|
56
|
-
params[@name] = @default
|
57
|
-
end
|
58
|
-
params
|
59
|
-
end
|
60
|
-
|
61
|
-
def validate_param_value(value)
|
62
|
-
case @type
|
63
|
-
when TYPE_NUMBER
|
64
|
-
return validate_param_value_number(value)
|
65
|
-
when TYPE_INTEGER
|
66
|
-
return validate_param_value_integer(value)
|
67
|
-
when TYPE_BOOLEAN
|
68
|
-
return validate_param_value_boolean(value)
|
69
|
-
when TYPE_DATE_TIME
|
70
|
-
return validate_param_value_date_time(value)
|
71
|
-
else
|
72
|
-
return validate_param_value_string(value)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Validate a boolean parameter
|
77
|
-
def validate_param_value_boolean(value)
|
78
|
-
if (value == 'true') || value.is_a?(TrueClass)
|
79
|
-
return true
|
80
|
-
elsif (value == 'false') || value.is_a?(FalseClass)
|
81
|
-
return false
|
82
|
-
else
|
83
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be an boolean but is [#{value}]")
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# Validate an integer parameter
|
88
|
-
def validate_param_value_integer(value)
|
89
|
-
begin
|
90
|
-
f = Float(value)
|
91
|
-
i = Integer(value)
|
92
|
-
if f == i
|
93
|
-
i
|
94
|
-
else
|
95
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be an integer but is [#{value}]")
|
96
|
-
end
|
97
|
-
value = Integer(value)
|
98
|
-
validate_numerical_value(value)
|
99
|
-
value
|
100
|
-
rescue ArgumentError
|
101
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be an integer but is [#{value}]")
|
102
|
-
rescue TypeError
|
103
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be an integer but is [#{value}]")
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# Validate a number parameter
|
108
|
-
def validate_param_value_number(value)
|
109
|
-
begin
|
110
|
-
value = Float(value)
|
111
|
-
validate_numerical_value(value)
|
112
|
-
return value
|
113
|
-
rescue ArgumentError
|
114
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be a float but is [#{value}]")
|
115
|
-
rescue TypeError
|
116
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be a float but is [#{value}]")
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Validate a numerical value
|
121
|
-
# @param value [Numeric] the value
|
122
|
-
def validate_numerical_value(value)
|
123
|
-
validate_numerical_value_internal(
|
124
|
-
value,
|
125
|
-
PARAMS_MINIMUM,
|
126
|
-
PARAMS_EXCLUSIVE_MINIMUM,
|
127
|
-
'>=',
|
128
|
-
'>')
|
129
|
-
validate_numerical_value_internal(
|
130
|
-
value,
|
131
|
-
PARAMS_MAXIMUM,
|
132
|
-
PARAMS_EXCLUSIVE_MAXIMUM,
|
133
|
-
'<=',
|
134
|
-
'<')
|
135
|
-
end
|
136
|
-
|
137
|
-
# Validate a date time parameter
|
138
|
-
def validate_param_value_date_time(value)
|
139
|
-
begin
|
140
|
-
DateTime.rfc3339(value)
|
141
|
-
rescue ArgumentError
|
142
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be a date time but is [#{value}]")
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# Validate a string parameter
|
147
|
-
def validate_param_value_string(value)
|
148
|
-
if value
|
149
|
-
validate_param_value_string_length(value, PARAMS_MIN_LENGTH, '>=')
|
150
|
-
validate_param_value_string_length(value, PARAMS_MAX_LENGTH, '<=')
|
151
|
-
end
|
152
|
-
value
|
153
|
-
end
|
154
|
-
|
155
|
-
# Validate the length of a string parameter
|
156
|
-
# @param value the value to check
|
157
|
-
# @param limit_param_name [Symbol] the param that contain the value to compare to
|
158
|
-
# @param limit_param_method [String] the comparison method to call
|
159
|
-
def validate_param_value_string_length(value, limit_param_name, limit_param_method)
|
160
|
-
if @params.key? limit_param_name
|
161
|
-
target_value = @params[limit_param_name]
|
162
|
-
unless value.length.send(limit_param_method, target_value)
|
163
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] length should be #{limit_param_method} than #{target_value} but is #{value.length} for [#{value}]")
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Validate the value of a number
|
169
|
-
# @param value the value to check
|
170
|
-
# @param limit_param_name [Symbol] the param that contain the value to compare to
|
171
|
-
# @param exclusive_limit_param_name [Symbol] the param that indicates if the comparison is absolute
|
172
|
-
# @param limit_param_method [String] the comparison method to call
|
173
|
-
# @param exclusive_limit_param_method [String] the absolute comparison method to call
|
174
|
-
def validate_numerical_value_internal(value, limit_param_name, exclusive_limit_param_name, limit_param_method, exclusive_limit_param_method)
|
175
|
-
if @params.key? limit_param_name
|
176
|
-
target_value = @params[limit_param_name]
|
177
|
-
method_to_call = @params[exclusive_limit_param_name] ? exclusive_limit_param_method : limit_param_method
|
178
|
-
unless value.send(method_to_call, target_value)
|
179
|
-
raise SwaggerInvalidException.new("Parameter [#{@name}] should be #{method_to_call} than [#{target_value}] but is [#{value}]")
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
end
|
185
|
-
|
186
|
-
end
|
187
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
require_relative 'swagger-invalid-exception'
|
4
|
-
|
5
|
-
module Sinatra
|
6
|
-
|
7
|
-
module SwaggerExposer
|
8
|
-
|
9
|
-
# A preprocessor for a request, apply the parameter preprocessor then execute the query code
|
10
|
-
class SwaggerRequestPreprocessor
|
11
|
-
|
12
|
-
attr_reader :preprocessors
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@preprocessors = []
|
16
|
-
end
|
17
|
-
|
18
|
-
def add_preprocessor(preprocessor)
|
19
|
-
@preprocessors << preprocessor
|
20
|
-
end
|
21
|
-
|
22
|
-
# Run the preprocessor the call the route content
|
23
|
-
# @param app the sinatra app being run
|
24
|
-
# @params block_params [Array] the block parameters
|
25
|
-
# @param block the block containing the route content
|
26
|
-
def run(app, block_params, &block)
|
27
|
-
parsed_body = {}
|
28
|
-
if app.env['CONTENT_TYPE'] == 'application/json'
|
29
|
-
body = app.request.body.read
|
30
|
-
unless body.empty?
|
31
|
-
parsed_body = JSON.parse(body)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
app.params['parsed_body'] = parsed_body
|
35
|
-
unless @preprocessors.empty?
|
36
|
-
@preprocessors.each do |preprocessor|
|
37
|
-
begin
|
38
|
-
preprocessor.run(app, parsed_body)
|
39
|
-
rescue SwaggerInvalidException => e
|
40
|
-
app.content_type :json
|
41
|
-
return [400, {:code => 400, :message => e.message}.to_json]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
if block
|
46
|
-
# Execute the block in the context of the app
|
47
|
-
app.instance_exec(*block_params, &block)
|
48
|
-
else
|
49
|
-
''
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require_relative 'swagger-utilities'
|
2
|
-
require_relative 'swagger-invalid-exception'
|
3
|
-
|
4
|
-
module Sinatra
|
5
|
-
|
6
|
-
module SwaggerExposer
|
7
|
-
|
8
|
-
# A property of a type
|
9
|
-
class SwaggerTypeProperty
|
10
|
-
|
11
|
-
include SwaggerUtilities
|
12
|
-
|
13
|
-
OTHER_PROPERTIES = [:example, :description, :format, :minLength, :maxLength]
|
14
|
-
PROPERTIES = [:type] + OTHER_PROPERTIES
|
15
|
-
|
16
|
-
def initialize(type_name, property_name, property_properties, known_types)
|
17
|
-
@name = property_name
|
18
|
-
|
19
|
-
unless property_properties.is_a? Hash
|
20
|
-
raise SwaggerInvalidException.new("Property [#{property_name}] value [#{property_properties}] of [#{type_name}] should be a hash")
|
21
|
-
end
|
22
|
-
|
23
|
-
if property_properties.key? :type
|
24
|
-
get_type(property_properties[:type], PRIMITIVE_TYPES + known_types)
|
25
|
-
end
|
26
|
-
|
27
|
-
white_list_params(property_properties, PROPERTIES)
|
28
|
-
|
29
|
-
@other_properties = property_properties.select do |key, value|
|
30
|
-
OTHER_PROPERTIES.include? key
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_swagger
|
36
|
-
result = @other_properties.clone
|
37
|
-
|
38
|
-
if @type
|
39
|
-
if @type == 'array'
|
40
|
-
result[:type] = 'array'
|
41
|
-
if @items
|
42
|
-
if PRIMITIVE_TYPES.include? @items
|
43
|
-
result[:items] = {:type => @items}
|
44
|
-
else
|
45
|
-
result[:items] = ref_to_type(@items)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
else
|
49
|
-
if PRIMITIVE_TYPES.include? @type
|
50
|
-
result[:type] = @type
|
51
|
-
else
|
52
|
-
result['$ref'] = "#/definitions/#{@type}"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
result
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
{
|
62
|
-
:name => @name,
|
63
|
-
:type => @type,
|
64
|
-
:items => @items,
|
65
|
-
:other_properties => @other_properties,
|
66
|
-
}.to_json
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
@@ -1,125 +0,0 @@
|
|
1
|
-
require_relative 'swagger-invalid-exception'
|
2
|
-
require_relative 'swagger-type-property'
|
3
|
-
require_relative 'swagger-utilities'
|
4
|
-
|
5
|
-
module Sinatra
|
6
|
-
|
7
|
-
module SwaggerExposer
|
8
|
-
|
9
|
-
# A type
|
10
|
-
class SwaggerType
|
11
|
-
|
12
|
-
include SwaggerUtilities
|
13
|
-
|
14
|
-
PROPERTY_PROPERTIES = :properties
|
15
|
-
PROPERTY_REQUIRED = :required
|
16
|
-
PROPERTY_EXAMPLE = :example
|
17
|
-
PROPERTY_EXTENDS = :extends
|
18
|
-
PROPERTIES = [PROPERTY_PROPERTIES, PROPERTY_REQUIRED, PROPERTY_EXAMPLE, PROPERTY_EXTENDS]
|
19
|
-
|
20
|
-
def initialize(type_name, type_properties, known_types)
|
21
|
-
white_list_params(type_properties, PROPERTIES)
|
22
|
-
@properties = process_properties(type_name, type_properties, known_types)
|
23
|
-
@required = process_required(type_name, type_properties, @properties.keys)
|
24
|
-
@example = process_example(type_name, type_properties, @properties.keys)
|
25
|
-
@extends = process_extends(type_properties, known_types)
|
26
|
-
end
|
27
|
-
|
28
|
-
def process_properties(type_name, type_content, known_types)
|
29
|
-
possible_value = check_attribute_empty_or_bad(type_name, type_content, PROPERTY_PROPERTIES, Hash)
|
30
|
-
if possible_value
|
31
|
-
possible_value
|
32
|
-
else
|
33
|
-
result = {}
|
34
|
-
type_content[PROPERTY_PROPERTIES].each_pair do |property_name, property_properties|
|
35
|
-
result[property_name.to_s] = SwaggerTypeProperty.new(type_name, property_name, property_properties, known_types)
|
36
|
-
end
|
37
|
-
result
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def process_required(type_name, type_content, properties_names)
|
42
|
-
possible_value = check_attribute_empty_or_bad(type_name, type_content, PROPERTY_REQUIRED, Array)
|
43
|
-
if possible_value
|
44
|
-
possible_value
|
45
|
-
else
|
46
|
-
type_content[PROPERTY_REQUIRED].each do |property_name|
|
47
|
-
property_name = property_name.to_s
|
48
|
-
unless properties_names.include? property_name
|
49
|
-
raise SwaggerInvalidException.new("Required property [#{property_name}] of [#{type_name}] is unknown#{list_or_none(properties_names, 'properties')}")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
type_content[PROPERTY_REQUIRED]
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def process_example(type_name, type_content, properties_names)
|
57
|
-
possible_value = check_attribute_empty_or_bad(type_name, type_content, PROPERTY_EXAMPLE, Hash)
|
58
|
-
if possible_value
|
59
|
-
possible_value
|
60
|
-
else
|
61
|
-
type_content[PROPERTY_EXAMPLE].each_pair do |property_name, property_value|
|
62
|
-
property_name = property_name.to_s
|
63
|
-
unless properties_names.include? property_name
|
64
|
-
raise SwaggerInvalidException.new("Example property [#{property_name}] with value [#{property_value}] of [#{type_name}] is unknown#{list_or_none(properties_names, 'properties')}")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
type_content[PROPERTY_EXAMPLE]
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def check_attribute_empty_or_bad(type_name, type_content, attribute_name, attribute_class)
|
72
|
-
if !type_content.key?(attribute_name)
|
73
|
-
attribute_class.new
|
74
|
-
elsif !type_content[attribute_name].is_a? attribute_class
|
75
|
-
raise SwaggerInvalidException.new("Attribute [#{attribute_name}] of #{type_name} is not an hash: #{type_content[attribute_name]}")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def process_extends(type_properties, known_types)
|
80
|
-
if type_properties.key? PROPERTY_EXTENDS
|
81
|
-
check_type(type_properties[PROPERTY_EXTENDS], known_types)
|
82
|
-
@extends = type_properties[PROPERTY_EXTENDS]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def to_swagger
|
87
|
-
result = {:type => 'object'}
|
88
|
-
|
89
|
-
unless @properties.empty?
|
90
|
-
result[PROPERTY_PROPERTIES] = hash_to_swagger(@properties)
|
91
|
-
end
|
92
|
-
|
93
|
-
unless @required.empty?
|
94
|
-
result[PROPERTY_REQUIRED] = @required
|
95
|
-
end
|
96
|
-
|
97
|
-
unless @example.empty?
|
98
|
-
result[PROPERTY_EXAMPLE] = @example
|
99
|
-
end
|
100
|
-
|
101
|
-
if @extends
|
102
|
-
result = {
|
103
|
-
:allOf => [
|
104
|
-
ref_to_type(@extends),
|
105
|
-
result
|
106
|
-
]
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
result
|
111
|
-
end
|
112
|
-
|
113
|
-
def to_s
|
114
|
-
{
|
115
|
-
:properties => @properties,
|
116
|
-
:required => @required,
|
117
|
-
:example => @example,
|
118
|
-
}.to_json
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
end
|