grape-swagger 0.20.3 → 0.21.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/.rubocop_todo.yml +10 -10
- data/.travis.yml +8 -3
- data/CHANGELOG.md +27 -0
- data/Gemfile +2 -0
- data/README.md +111 -12
- data/UPGRADING.md +9 -0
- data/grape-swagger.gemspec +1 -3
- data/lib/grape-swagger.rb +8 -1
- data/lib/grape-swagger/doc_methods/optional_object.rb +14 -2
- data/lib/grape-swagger/doc_methods/parse_params.rb +3 -4
- data/lib/grape-swagger/doc_methods/path_string.rb +4 -3
- data/lib/grape-swagger/endpoint.rb +25 -55
- data/lib/grape-swagger/errors.rb +3 -0
- data/lib/grape-swagger/grape/route.rb +2 -1
- data/lib/grape-swagger/model_parsers.rb +33 -0
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/issues/403_versions_spec.rb +20 -4
- data/spec/lib/model_parsers_spec.rb +102 -0
- data/spec/lib/optional_object_spec.rb +15 -11
- data/spec/lib/path_string_spec.rb +72 -18
- data/spec/lib/produces_consumes_spec.rb +10 -5
- data/spec/spec_helper.rb +4 -2
- data/spec/support/empty_model_parser.rb +20 -0
- data/spec/support/mock_parser.rb +22 -0
- data/spec/support/model_parsers/entity_parser.rb +325 -0
- data/spec/support/{api_swagger_v2_result.rb → model_parsers/mock_parser.rb} +186 -60
- data/spec/support/model_parsers/representable_parser.rb +394 -0
- data/spec/support/the_paths_definitions.rb +7 -3
- data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +5 -4
- data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +3 -3
- data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +5 -3
- data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +25 -14
- data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +22 -12
- data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +30 -18
- data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +6 -3
- data/spec/swagger_v2/api_swagger_v2_response_spec.rb +13 -40
- data/spec/swagger_v2/api_swagger_v2_spec.rb +4 -2
- data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +6 -36
- data/spec/swagger_v2/default_api_spec.rb +10 -2
- data/spec/swagger_v2/endpoint_versioned_path_spec.rb +30 -0
- data/spec/swagger_v2/errors_spec.rb +75 -0
- data/spec/swagger_v2/hide_api_spec.rb +22 -4
- data/spec/swagger_v2/mounted_target_class_spec.rb +6 -2
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +6 -3
- data/spec/swagger_v2/namespace_tags_spec.rb +6 -3
- data/spec/swagger_v2/params_array_spec.rb +4 -2
- data/spec/swagger_v2/params_hash_spec.rb +4 -2
- data/spec/swagger_v2/params_nested_spec.rb +4 -2
- data/spec/swagger_v2/simple_mounted_api_spec.rb +66 -24
- metadata +23 -40
- data/spec/support/the_api_entities.rb +0 -50
- data/spec/swagger_v2/response_model_spec.rb +0 -208
@@ -28,7 +28,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
|
|
28
28
|
'application/json',
|
29
29
|
'application/octet-stream',
|
30
30
|
'text/plain'
|
31
|
-
]
|
31
|
+
]
|
32
|
+
)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -59,7 +60,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
|
|
59
60
|
'application/json',
|
60
61
|
'application/octet-stream',
|
61
62
|
'text/plain'
|
62
|
-
]
|
63
|
+
]
|
64
|
+
)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
@@ -82,7 +84,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
|
|
82
84
|
'application/json',
|
83
85
|
'application/octet-stream',
|
84
86
|
'text/plain'
|
85
|
-
]
|
87
|
+
]
|
88
|
+
)
|
86
89
|
end
|
87
90
|
|
88
91
|
subject do
|
@@ -93,7 +96,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
|
|
93
96
|
'application/json',
|
94
97
|
'application/octet-stream',
|
95
98
|
:txt
|
96
|
-
]
|
99
|
+
]
|
100
|
+
)
|
97
101
|
end
|
98
102
|
|
99
103
|
specify do
|
@@ -103,7 +107,8 @@ describe GrapeSwagger::DocMethods::ProducesConsumes do
|
|
103
107
|
'application/json',
|
104
108
|
'application/octet-stream',
|
105
109
|
'text/plain'
|
106
|
-
]
|
110
|
+
]
|
111
|
+
)
|
107
112
|
end
|
108
113
|
end
|
109
114
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
2
|
|
3
|
-
|
3
|
+
MODEL_PARSER = ENV.key?('MODEL_PARSER') ? ENV['MODEL_PARSER'].to_s.downcase.sub('grape-swagger-', '') : 'mock'
|
4
4
|
|
5
5
|
require 'grape'
|
6
6
|
require 'grape-swagger'
|
7
|
-
|
7
|
+
Dir[File.join(Dir.getwd, 'spec/support/*.rb')].each { |f| require f }
|
8
|
+
require "grape-swagger/#{MODEL_PARSER}" if MODEL_PARSER != 'mock'
|
9
|
+
require File.join(Dir.getwd, "spec/support/model_parsers/#{MODEL_PARSER}_parser.rb")
|
8
10
|
|
9
11
|
Bundler.setup :default, :test
|
10
12
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class EmptyClass
|
2
|
+
end
|
3
|
+
|
4
|
+
module GrapeSwagger
|
5
|
+
class EmptyModelParser
|
6
|
+
attr_reader :model
|
7
|
+
attr_reader :endpoint
|
8
|
+
|
9
|
+
def initialize(model, endpoint)
|
10
|
+
@model = model
|
11
|
+
@endpoint = endpoint
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
GrapeSwagger.model_parsers.register(GrapeSwagger::EmptyModelParser, EmptyClass)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GrapeSwagger
|
2
|
+
class MockParser
|
3
|
+
attr_reader :model
|
4
|
+
attr_reader :endpoint
|
5
|
+
|
6
|
+
def initialize(model, endpoint)
|
7
|
+
@model = model
|
8
|
+
@endpoint = endpoint
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
{
|
13
|
+
mock_data: {
|
14
|
+
type: :string,
|
15
|
+
description: "it's a mock"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
GrapeSwagger.model_parsers.register(GrapeSwagger::MockParser, OpenStruct)
|
@@ -0,0 +1,325 @@
|
|
1
|
+
RSpec.shared_context 'entity swagger example' do
|
2
|
+
before :all do
|
3
|
+
module Entities
|
4
|
+
class Something < Grape::Entity
|
5
|
+
expose :id, documentation: { type: Integer, desc: 'Identity of Something' }
|
6
|
+
expose :text, documentation: { type: String, desc: 'Content of something.' }
|
7
|
+
expose :links, documentation: { type: 'link', is_array: true }
|
8
|
+
expose :others, documentation: { type: 'text', is_array: false }
|
9
|
+
end
|
10
|
+
|
11
|
+
class EnumValues < Grape::Entity
|
12
|
+
expose :gender, documentation: { type: 'string', desc: 'Content of something.', values: %w(Male Female) }
|
13
|
+
expose :number, documentation: { type: 'integer', desc: 'Content of something.', values: [1, 2] }
|
14
|
+
end
|
15
|
+
|
16
|
+
class AliasedThing < Grape::Entity
|
17
|
+
expose :something, as: :post, using: Entities::Something, documentation: { type: 'Something', desc: 'Reference to something.' }
|
18
|
+
end
|
19
|
+
|
20
|
+
class FourthLevel < Grape::Entity
|
21
|
+
expose :text, documentation: { type: 'string' }
|
22
|
+
end
|
23
|
+
|
24
|
+
class ThirdLevel < Grape::Entity
|
25
|
+
expose :parts, using: Entities::FourthLevel, documentation: { type: 'FourthLevel' }
|
26
|
+
end
|
27
|
+
|
28
|
+
class SecondLevel < Grape::Entity
|
29
|
+
expose :parts, using: Entities::ThirdLevel, documentation: { type: 'ThirdLevel' }
|
30
|
+
end
|
31
|
+
|
32
|
+
class FirstLevel < Grape::Entity
|
33
|
+
expose :parts, using: Entities::SecondLevel, documentation: { type: 'SecondLevel' }
|
34
|
+
end
|
35
|
+
|
36
|
+
class QueryInputElement < Grape::Entity
|
37
|
+
expose :key, documentation: {
|
38
|
+
type: String, desc: 'Name of parameter', required: true
|
39
|
+
}
|
40
|
+
expose :value, documentation: {
|
41
|
+
type: String, desc: 'Value of parameter', required: true
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
class QueryInput < Grape::Entity
|
46
|
+
expose :elements, using: Entities::QueryInputElement, documentation: {
|
47
|
+
type: 'QueryInputElement',
|
48
|
+
desc: 'Set of configuration',
|
49
|
+
param_type: 'body',
|
50
|
+
is_array: true,
|
51
|
+
required: true
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
class ApiError < Grape::Entity
|
56
|
+
expose :code, documentation: { type: Integer, desc: 'status code' }
|
57
|
+
expose :message, documentation: { type: String, desc: 'error message' }
|
58
|
+
end
|
59
|
+
|
60
|
+
class SecondApiError < Grape::Entity
|
61
|
+
expose :code, documentation: { type: Integer }
|
62
|
+
expose :severity, documentation: { type: String }
|
63
|
+
expose :message, documentation: { type: String }
|
64
|
+
end
|
65
|
+
|
66
|
+
class ResponseItem < Grape::Entity
|
67
|
+
expose :id, documentation: { type: Integer }
|
68
|
+
expose :name, documentation: { type: String }
|
69
|
+
end
|
70
|
+
|
71
|
+
class OtherItem < Grape::Entity
|
72
|
+
expose :key, documentation: { type: Integer }
|
73
|
+
expose :symbol, documentation: { type: String }
|
74
|
+
end
|
75
|
+
|
76
|
+
class UseResponse < Grape::Entity
|
77
|
+
expose :description, documentation: { type: String }
|
78
|
+
expose :items, as: '$responses', using: Entities::ResponseItem, documentation: { is_array: true }
|
79
|
+
end
|
80
|
+
|
81
|
+
class UseItemResponseAsType < Grape::Entity
|
82
|
+
expose :description, documentation: { type: String }
|
83
|
+
expose :responses, documentation: { type: Entities::ResponseItem, is_array: false }
|
84
|
+
end
|
85
|
+
|
86
|
+
class UseAddress < Grape::Entity
|
87
|
+
expose :street, documentation: { type: String, desc: 'street' }
|
88
|
+
expose :postcode, documentation: { type: String, desc: 'postcode' }
|
89
|
+
expose :city, documentation: { type: String, desc: 'city' }
|
90
|
+
expose :country, documentation: { type: String, desc: 'country' }
|
91
|
+
end
|
92
|
+
|
93
|
+
class UseNestedWithAddress < Grape::Entity
|
94
|
+
expose :name, documentation: { type: String }
|
95
|
+
expose :address, using: Entities::UseAddress
|
96
|
+
end
|
97
|
+
|
98
|
+
class TypedDefinition < Grape::Entity
|
99
|
+
expose :prop_integer, documentation: { type: Integer, desc: 'prop_integer description' }
|
100
|
+
expose :prop_long, documentation: { type: Numeric, desc: 'prop_long description' }
|
101
|
+
expose :prop_float, documentation: { type: Float, desc: 'prop_float description' }
|
102
|
+
expose :prop_double, documentation: { type: BigDecimal, desc: 'prop_double description' }
|
103
|
+
expose :prop_string, documentation: { type: String, desc: 'prop_string description' }
|
104
|
+
expose :prop_symbol, documentation: { type: Symbol, desc: 'prop_symbol description' }
|
105
|
+
expose :prop_date, documentation: { type: Date, desc: 'prop_date description' }
|
106
|
+
expose :prop_date_time, documentation: { type: DateTime, desc: 'prop_date_time description' }
|
107
|
+
expose :prop_time, documentation: { type: Time, desc: 'prop_time description' }
|
108
|
+
expose :prop_password, documentation: { type: 'password', desc: 'prop_password description' }
|
109
|
+
expose :prop_email, documentation: { type: 'email', desc: 'prop_email description' }
|
110
|
+
expose :prop_boolean, documentation: { type: Virtus::Attribute::Boolean, desc: 'prop_boolean description' }
|
111
|
+
expose :prop_file, documentation: { type: File, desc: 'prop_file description' }
|
112
|
+
expose :prop_json, documentation: { type: JSON, desc: 'prop_json description' }
|
113
|
+
end
|
114
|
+
|
115
|
+
class RecursiveModel < Grape::Entity
|
116
|
+
expose :name, documentation: { type: String, desc: 'The name.' }
|
117
|
+
expose :children, using: self, documentation: { type: 'RecursiveModel', is_array: true, desc: 'The child nodes.' }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
let(:swagger_definitions_models) do
|
123
|
+
{
|
124
|
+
'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } } },
|
125
|
+
'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
|
126
|
+
'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } } },
|
127
|
+
'RecursiveModel' => { 'type' => 'object', 'properties' => { 'name' => { 'type' => 'string', 'description' => 'The name.' }, 'children' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/RecursiveModel' }, 'description' => 'The child nodes.' } } }
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:swagger_nested_type) do
|
132
|
+
{
|
133
|
+
'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
|
134
|
+
'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
|
135
|
+
'UseItemResponseAsType' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, 'responses' => { '$ref' => '#/definitions/ResponseItem' } }, 'description' => 'This returns something' }
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
let(:swagger_entity_as_response_object) do
|
140
|
+
{
|
141
|
+
'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } }, 'description' => 'This returns something' },
|
142
|
+
'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
|
143
|
+
'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } }, 'description' => 'This returns something' }
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
let(:swagger_params_as_response_object) do
|
148
|
+
{
|
149
|
+
'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'description' => 'status code', 'type' => 'integer', 'format' => 'int32' }, 'message' => { 'description' => 'error message', 'type' => 'string' } }, 'description' => 'This returns something' }
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
let(:swagger_typed_defintion) do
|
154
|
+
{
|
155
|
+
'prop_boolean' => { 'description' => 'prop_boolean description', 'type' => 'boolean' },
|
156
|
+
'prop_date' => { 'description' => 'prop_date description', 'type' => 'string', 'format' => 'date' },
|
157
|
+
'prop_date_time' => { 'description' => 'prop_date_time description', 'type' => 'string', 'format' => 'date-time' },
|
158
|
+
'prop_double' => { 'description' => 'prop_double description', 'type' => 'number', 'format' => 'double' },
|
159
|
+
'prop_email' => { 'description' => 'prop_email description', 'type' => 'string', 'format' => 'email' },
|
160
|
+
'prop_file' => { 'description' => 'prop_file description', 'type' => 'file' },
|
161
|
+
'prop_float' => { 'description' => 'prop_float description', 'type' => 'number', 'format' => 'float' },
|
162
|
+
'prop_integer' => { 'description' => 'prop_integer description', 'type' => 'integer', 'format' => 'int32' },
|
163
|
+
'prop_json' => { 'description' => 'prop_json description', 'type' => 'json' },
|
164
|
+
'prop_long' => { 'description' => 'prop_long description', 'type' => 'integer', 'format' => 'int64' },
|
165
|
+
'prop_password' => { 'description' => 'prop_password description', 'type' => 'string', 'format' => 'password' },
|
166
|
+
'prop_string' => { 'description' => 'prop_string description', 'type' => 'string' },
|
167
|
+
'prop_symbol' => { 'description' => 'prop_symbol description', 'type' => 'string' },
|
168
|
+
'prop_time' => { 'description' => 'prop_time description', 'type' => 'string', 'format' => 'date-time' }
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
let(:swagger_json) do
|
173
|
+
{
|
174
|
+
'info' => {
|
175
|
+
'title' => 'The API title to be displayed on the API homepage.',
|
176
|
+
'description' => 'A description of the API.',
|
177
|
+
'termsOfServiceUrl' => 'www.The-URL-of-the-terms-and-service.com',
|
178
|
+
'contact' => { 'name' => 'Contact name', 'email' => 'Contact@email.com', 'url' => 'Contact URL' },
|
179
|
+
'license' => { 'name' => 'The name of the license.', 'url' => 'www.The-URL-of-the-license.org' },
|
180
|
+
'version' => '0.0.1'
|
181
|
+
},
|
182
|
+
'swagger' => '2.0',
|
183
|
+
'produces' => ['application/json'],
|
184
|
+
'host' => 'example.org',
|
185
|
+
'basePath' => '/api',
|
186
|
+
'tags' => [
|
187
|
+
{ 'name' => 'other_thing', 'description' => 'Operations about other_things' },
|
188
|
+
{ 'name' => 'thing', 'description' => 'Operations about things' },
|
189
|
+
{ 'name' => 'thing2', 'description' => 'Operations about thing2s' },
|
190
|
+
{ 'name' => 'dummy', 'description' => 'Operations about dummies' }
|
191
|
+
],
|
192
|
+
'paths' => {
|
193
|
+
'/v3/other_thing/{elements}' => {
|
194
|
+
'get' => {
|
195
|
+
'summary' => 'nested route inside namespace',
|
196
|
+
'description' => 'nested route inside namespace',
|
197
|
+
'produces' => ['application/json'],
|
198
|
+
'parameters' => [{ 'in' => 'body', 'name' => 'elements', 'description' => 'Set of configuration', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }],
|
199
|
+
'responses' => { '200' => { 'description' => 'nested route inside namespace', 'schema' => { '$ref' => '#/definitions/QueryInput' } } },
|
200
|
+
'tags' => ['other_thing'],
|
201
|
+
'operationId' => 'getV3OtherThingElements',
|
202
|
+
'x-amazon-apigateway-auth' => { 'type' => 'none' },
|
203
|
+
'x-amazon-apigateway-integration' => { 'type' => 'aws', 'uri' => 'foo_bar_uri', 'httpMethod' => 'get' }
|
204
|
+
}
|
205
|
+
},
|
206
|
+
'/thing' => {
|
207
|
+
'get' => {
|
208
|
+
'summary' => 'This gets Things.',
|
209
|
+
'description' => 'This gets Things.',
|
210
|
+
'produces' => ['application/json'],
|
211
|
+
'parameters' => [
|
212
|
+
{ 'in' => 'query', 'name' => 'id', 'description' => 'Identity of Something', 'type' => 'integer', 'format' => 'int32', 'required' => false },
|
213
|
+
{ 'in' => 'query', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => false },
|
214
|
+
{ 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'link' }, 'required' => false },
|
215
|
+
{ 'in' => 'query', 'name' => 'others', 'type' => 'text', 'required' => false }
|
216
|
+
],
|
217
|
+
'responses' => { '200' => { 'description' => 'This gets Things.' }, '401' => { 'description' => 'Unauthorized', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
|
218
|
+
'tags' => ['thing'],
|
219
|
+
'operationId' => 'getThing'
|
220
|
+
},
|
221
|
+
'post' => {
|
222
|
+
'summary' => 'This creates Thing.',
|
223
|
+
'description' => 'This creates Thing.',
|
224
|
+
'produces' => ['application/json'],
|
225
|
+
'consumes' => ['application/json'],
|
226
|
+
'parameters' => [
|
227
|
+
{ 'in' => 'formData', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => true },
|
228
|
+
{ 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }
|
229
|
+
],
|
230
|
+
'responses' => { '201' => { 'description' => 'This creates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } }, '422' => { 'description' => 'Unprocessible Entity' } },
|
231
|
+
'tags' => ['thing'],
|
232
|
+
'operationId' => 'postThing'
|
233
|
+
}
|
234
|
+
},
|
235
|
+
'/thing/{id}' => {
|
236
|
+
'get' => {
|
237
|
+
'summary' => 'This gets Thing.',
|
238
|
+
'description' => 'This gets Thing.',
|
239
|
+
'produces' => ['application/json'],
|
240
|
+
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
241
|
+
'responses' => { '200' => { 'description' => 'getting a single thing' }, '401' => { 'description' => 'Unauthorized' } },
|
242
|
+
'tags' => ['thing'],
|
243
|
+
'operationId' => 'getThingId'
|
244
|
+
},
|
245
|
+
'put' => {
|
246
|
+
'summary' => 'This updates Thing.',
|
247
|
+
'description' => 'This updates Thing.',
|
248
|
+
'produces' => ['application/json'],
|
249
|
+
'consumes' => ['application/json'],
|
250
|
+
'parameters' => [
|
251
|
+
{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true },
|
252
|
+
{ 'in' => 'formData', 'name' => 'text', 'description' => 'Content of something.', 'type' => 'string', 'required' => false },
|
253
|
+
{ 'in' => 'formData', 'name' => 'links', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false }
|
254
|
+
],
|
255
|
+
'responses' => { '200' => { 'description' => 'This updates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
|
256
|
+
'tags' => ['thing'],
|
257
|
+
'operationId' => 'putThingId'
|
258
|
+
},
|
259
|
+
'delete' => {
|
260
|
+
'summary' => 'This deletes Thing.',
|
261
|
+
'description' => 'This deletes Thing.',
|
262
|
+
'produces' => ['application/json'],
|
263
|
+
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
264
|
+
'responses' => { '200' => { 'description' => 'This deletes Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
|
265
|
+
'tags' => ['thing'],
|
266
|
+
'operationId' => 'deleteThingId'
|
267
|
+
}
|
268
|
+
},
|
269
|
+
'/thing2' => {
|
270
|
+
'get' => {
|
271
|
+
'summary' => 'This gets Things.',
|
272
|
+
'description' => 'This gets Things.',
|
273
|
+
'produces' => ['application/json'],
|
274
|
+
'responses' => { '200' => { 'description' => 'get Horses', 'schema' => { '$ref' => '#/definitions/Something' } }, '401' => { 'description' => 'HorsesOutError', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
|
275
|
+
'tags' => ['thing2'],
|
276
|
+
'operationId' => 'getThing2'
|
277
|
+
}
|
278
|
+
},
|
279
|
+
'/dummy/{id}' => {
|
280
|
+
'delete' => {
|
281
|
+
'summary' => 'dummy route.',
|
282
|
+
'description' => 'dummy route.',
|
283
|
+
'produces' => ['application/json'],
|
284
|
+
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
285
|
+
'responses' => { '204' => { 'description' => 'dummy route.' }, '401' => { 'description' => 'Unauthorized' } },
|
286
|
+
'tags' => ['dummy'],
|
287
|
+
'operationId' => 'deleteDummyId'
|
288
|
+
}
|
289
|
+
}
|
290
|
+
},
|
291
|
+
'definitions' => {
|
292
|
+
'QueryInput' => {
|
293
|
+
'type' => 'object',
|
294
|
+
'properties' => { 'elements' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/QueryInputElement' }, 'description' => 'Set of configuration' } },
|
295
|
+
'description' => 'nested route inside namespace'
|
296
|
+
},
|
297
|
+
'QueryInputElement' => {
|
298
|
+
'type' => 'object',
|
299
|
+
'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } }
|
300
|
+
},
|
301
|
+
'ApiError' => {
|
302
|
+
'type' => 'object',
|
303
|
+
'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } },
|
304
|
+
'description' => 'This gets Things.'
|
305
|
+
},
|
306
|
+
'Something' => {
|
307
|
+
'type' => 'object',
|
308
|
+
'properties' => {
|
309
|
+
'id' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'Identity of Something' },
|
310
|
+
'text' => { 'type' => 'string', 'description' => 'Content of something.' },
|
311
|
+
'links' => { 'type' => 'link' },
|
312
|
+
'others' => { 'type' => 'text' }
|
313
|
+
},
|
314
|
+
'description' => 'This gets Things.'
|
315
|
+
}
|
316
|
+
}
|
317
|
+
}
|
318
|
+
end
|
319
|
+
|
320
|
+
let(:http_verbs) { %w(get post put delete) }
|
321
|
+
end
|
322
|
+
|
323
|
+
def mounted_paths
|
324
|
+
%w( /thing /other_thing /dummy )
|
325
|
+
end
|
@@ -1,60 +1,164 @@
|
|
1
|
-
RSpec.shared_context 'swagger example' do
|
1
|
+
RSpec.shared_context 'mock swagger example' do
|
2
2
|
before :all do
|
3
3
|
module Entities
|
4
|
-
class Something <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
class Something < OpenStruct
|
5
|
+
class << self
|
6
|
+
# Representable doesn't have documentation method, mock this
|
7
|
+
def documentation
|
8
|
+
{
|
9
|
+
id: { type: Integer, desc: 'Identity of Something' },
|
10
|
+
text: { type: String, desc: 'Content of something.' },
|
11
|
+
links: { type: 'link', is_array: true },
|
12
|
+
others: { type: 'text', is_array: false }
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
9
16
|
end
|
10
17
|
|
11
|
-
class
|
12
|
-
|
13
|
-
|
18
|
+
class UseResponse < OpenStruct
|
19
|
+
class << self
|
20
|
+
def documentation
|
21
|
+
{
|
22
|
+
:description => { type: String },
|
23
|
+
'$responses' => { is_array: true }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
14
27
|
end
|
15
28
|
|
16
|
-
class
|
17
|
-
|
29
|
+
class ResponseItem < OpenStruct
|
30
|
+
class << self
|
31
|
+
def documentation
|
32
|
+
{
|
33
|
+
id: { type: Integer },
|
34
|
+
name: { type: String }
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
18
38
|
end
|
19
39
|
|
20
|
-
class
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
class
|
25
|
-
|
26
|
-
end
|
40
|
+
class UseNestedWithAddress < OpenStruct; end
|
41
|
+
class TypedDefinition < OpenStruct; end
|
42
|
+
class UseItemResponseAsType < OpenStruct; end
|
43
|
+
class OtherItem < OpenStruct; end
|
44
|
+
class EnumValues < OpenStruct; end
|
45
|
+
class AliasedThing < OpenStruct; end
|
46
|
+
class FourthLevel < OpenStruct; end
|
47
|
+
class ThirdLevel < OpenStruct; end
|
48
|
+
class SecondLevel < OpenStruct; end
|
49
|
+
class FirstLevel < OpenStruct; end
|
50
|
+
class QueryInputElement < OpenStruct; end
|
51
|
+
class QueryInput < OpenStruct; end
|
52
|
+
class ApiError < OpenStruct; end
|
53
|
+
class SecondApiError < OpenStruct; end
|
54
|
+
class RecursiveModel < OpenStruct; end
|
55
|
+
end
|
56
|
+
end
|
27
57
|
|
28
|
-
|
29
|
-
|
30
|
-
|
58
|
+
let(:swagger_definitions_models) do
|
59
|
+
{
|
60
|
+
'ApiError' => {
|
61
|
+
'type' => 'object',
|
62
|
+
'properties' => {
|
63
|
+
'mock_data' => {
|
64
|
+
'type' => 'string',
|
65
|
+
'description' => "it's a mock"
|
66
|
+
}
|
67
|
+
}
|
68
|
+
},
|
69
|
+
'RecursiveModel' => {
|
70
|
+
'type' => 'object',
|
71
|
+
'properties' => {
|
72
|
+
'mock_data' => {
|
73
|
+
'type' => 'string',
|
74
|
+
'description' => "it's a mock"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
},
|
78
|
+
'UseResponse' => {
|
79
|
+
'type' => 'object',
|
80
|
+
'properties' => {
|
81
|
+
'mock_data' => {
|
82
|
+
'type' => 'string',
|
83
|
+
'description' => "it's a mock"
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
31
89
|
|
32
|
-
|
33
|
-
|
34
|
-
|
90
|
+
let(:swagger_nested_type) do
|
91
|
+
{
|
92
|
+
'ApiError' => {
|
93
|
+
'type' => 'object',
|
94
|
+
'properties' => {
|
95
|
+
'mock_data' => {
|
96
|
+
'type' => 'string',
|
97
|
+
'description' => "it's a mock"
|
98
|
+
}
|
99
|
+
},
|
100
|
+
'description' => 'This returns something'
|
101
|
+
},
|
102
|
+
'UseItemResponseAsType' => {
|
103
|
+
'type' => 'object',
|
104
|
+
'properties' => {
|
105
|
+
'mock_data' => {
|
106
|
+
'type' => 'string',
|
107
|
+
'description' => "it's a mock"
|
108
|
+
}
|
109
|
+
},
|
110
|
+
'description' => 'This returns something'
|
111
|
+
}
|
112
|
+
}
|
113
|
+
end
|
35
114
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
115
|
+
let(:swagger_entity_as_response_object) do
|
116
|
+
{
|
117
|
+
'UseResponse' => {
|
118
|
+
'type' => 'object',
|
119
|
+
'properties' => {
|
120
|
+
'mock_data' => {
|
121
|
+
'type' => 'string',
|
122
|
+
'description' => "it's a mock"
|
123
|
+
}
|
124
|
+
},
|
125
|
+
'description' => 'This returns something'
|
126
|
+
},
|
127
|
+
'ApiError' => {
|
128
|
+
'type' => 'object',
|
129
|
+
'properties' => {
|
130
|
+
'mock_data' => {
|
131
|
+
'type' => 'string',
|
132
|
+
'description' => "it's a mock"
|
133
|
+
}
|
134
|
+
},
|
135
|
+
'description' => 'This returns something'
|
136
|
+
}
|
137
|
+
}
|
138
|
+
end
|
42
139
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
140
|
+
let(:swagger_params_as_response_object) do
|
141
|
+
{
|
142
|
+
'ApiError' => {
|
143
|
+
'type' => 'object',
|
144
|
+
'properties' => {
|
145
|
+
'mock_data' => {
|
146
|
+
'type' => 'string',
|
147
|
+
'description' => "it's a mock"
|
148
|
+
}
|
149
|
+
},
|
150
|
+
'description' => 'This returns something'
|
151
|
+
}
|
152
|
+
}
|
153
|
+
end
|
52
154
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
155
|
+
let(:swagger_typed_defintion) do
|
156
|
+
{
|
157
|
+
'mock_data' => {
|
158
|
+
'type' => 'string',
|
159
|
+
'description' => "it's a mock"
|
160
|
+
}
|
161
|
+
}
|
58
162
|
end
|
59
163
|
|
60
164
|
let(:swagger_json) do
|
@@ -80,6 +184,7 @@ RSpec.shared_context 'swagger example' do
|
|
80
184
|
'paths' => {
|
81
185
|
'/v3/other_thing/{elements}' => {
|
82
186
|
'get' => {
|
187
|
+
'summary' => 'nested route inside namespace',
|
83
188
|
'description' => 'nested route inside namespace',
|
84
189
|
'produces' => ['application/json'],
|
85
190
|
'parameters' => [{ 'in' => 'body', 'name' => 'elements', 'description' => 'Set of configuration', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => true }],
|
@@ -88,9 +193,11 @@ RSpec.shared_context 'swagger example' do
|
|
88
193
|
'operationId' => 'getV3OtherThingElements',
|
89
194
|
'x-amazon-apigateway-auth' => { 'type' => 'none' },
|
90
195
|
'x-amazon-apigateway-integration' => { 'type' => 'aws', 'uri' => 'foo_bar_uri', 'httpMethod' => 'get' }
|
91
|
-
}
|
196
|
+
}
|
197
|
+
},
|
92
198
|
'/thing' => {
|
93
199
|
'get' => {
|
200
|
+
'summary' => 'This gets Things.',
|
94
201
|
'description' => 'This gets Things.',
|
95
202
|
'produces' => ['application/json'],
|
96
203
|
'parameters' => [
|
@@ -104,6 +211,7 @@ RSpec.shared_context 'swagger example' do
|
|
104
211
|
'operationId' => 'getThing'
|
105
212
|
},
|
106
213
|
'post' => {
|
214
|
+
'summary' => 'This creates Thing.',
|
107
215
|
'description' => 'This creates Thing.',
|
108
216
|
'produces' => ['application/json'],
|
109
217
|
'consumes' => ['application/json'],
|
@@ -114,9 +222,11 @@ RSpec.shared_context 'swagger example' do
|
|
114
222
|
'responses' => { '201' => { 'description' => 'This creates Thing.', 'schema' => { '$ref' => '#/definitions/Something' } }, '422' => { 'description' => 'Unprocessible Entity' } },
|
115
223
|
'tags' => ['thing'],
|
116
224
|
'operationId' => 'postThing'
|
117
|
-
}
|
225
|
+
}
|
226
|
+
},
|
118
227
|
'/thing/{id}' => {
|
119
228
|
'get' => {
|
229
|
+
'summary' => 'This gets Thing.',
|
120
230
|
'description' => 'This gets Thing.',
|
121
231
|
'produces' => ['application/json'],
|
122
232
|
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
@@ -125,6 +235,7 @@ RSpec.shared_context 'swagger example' do
|
|
125
235
|
'operationId' => 'getThingId'
|
126
236
|
},
|
127
237
|
'put' => {
|
238
|
+
'summary' => 'This updates Thing.',
|
128
239
|
'description' => 'This updates Thing.',
|
129
240
|
'produces' => ['application/json'],
|
130
241
|
'consumes' => ['application/json'],
|
@@ -138,55 +249,70 @@ RSpec.shared_context 'swagger example' do
|
|
138
249
|
'operationId' => 'putThingId'
|
139
250
|
},
|
140
251
|
'delete' => {
|
252
|
+
'summary' => 'This deletes Thing.',
|
141
253
|
'description' => 'This deletes Thing.',
|
142
254
|
'produces' => ['application/json'],
|
143
255
|
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
144
256
|
'responses' => { '200' => { 'description' => 'This deletes Thing.', 'schema' => { '$ref' => '#/definitions/Something' } } },
|
145
257
|
'tags' => ['thing'],
|
146
258
|
'operationId' => 'deleteThingId'
|
147
|
-
}
|
259
|
+
}
|
260
|
+
},
|
148
261
|
'/thing2' => {
|
149
262
|
'get' => {
|
263
|
+
'summary' => 'This gets Things.',
|
150
264
|
'description' => 'This gets Things.',
|
151
265
|
'produces' => ['application/json'],
|
152
266
|
'responses' => { '200' => { 'description' => 'get Horses', 'schema' => { '$ref' => '#/definitions/Something' } }, '401' => { 'description' => 'HorsesOutError', 'schema' => { '$ref' => '#/definitions/ApiError' } } },
|
153
267
|
'tags' => ['thing2'],
|
154
268
|
'operationId' => 'getThing2'
|
155
|
-
}
|
269
|
+
}
|
270
|
+
},
|
156
271
|
'/dummy/{id}' => {
|
157
272
|
'delete' => {
|
273
|
+
'summary' => 'dummy route.',
|
158
274
|
'description' => 'dummy route.',
|
159
275
|
'produces' => ['application/json'],
|
160
276
|
'parameters' => [{ 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }],
|
161
277
|
'responses' => { '204' => { 'description' => 'dummy route.' }, '401' => { 'description' => 'Unauthorized' } },
|
162
278
|
'tags' => ['dummy'],
|
163
279
|
'operationId' => 'deleteDummyId'
|
164
|
-
}
|
280
|
+
}
|
281
|
+
}
|
282
|
+
},
|
165
283
|
'definitions' => {
|
166
284
|
'QueryInput' => {
|
167
285
|
'type' => 'object',
|
168
|
-
'properties' => {
|
286
|
+
'properties' => {
|
287
|
+
'mock_data' => {
|
288
|
+
'type' => 'string',
|
289
|
+
'description' => "it's a mock"
|
290
|
+
}
|
291
|
+
},
|
169
292
|
'description' => 'nested route inside namespace'
|
170
293
|
},
|
171
|
-
'QueryInputElement' => {
|
172
|
-
'type' => 'object',
|
173
|
-
'properties' => { 'key' => { 'type' => 'string', 'description' => 'Name of parameter' }, 'value' => { 'type' => 'string', 'description' => 'Value of parameter' } }
|
174
|
-
},
|
175
294
|
'ApiError' => {
|
176
295
|
'type' => 'object',
|
177
|
-
'properties' => {
|
296
|
+
'properties' => {
|
297
|
+
'mock_data' => {
|
298
|
+
'type' => 'string',
|
299
|
+
'description' => "it's a mock"
|
300
|
+
}
|
301
|
+
},
|
178
302
|
'description' => 'This gets Things.'
|
179
303
|
},
|
180
304
|
'Something' => {
|
181
305
|
'type' => 'object',
|
182
306
|
'properties' => {
|
183
|
-
'
|
184
|
-
|
185
|
-
|
186
|
-
|
307
|
+
'mock_data' => {
|
308
|
+
'type' => 'string',
|
309
|
+
'description' => "it's a mock"
|
310
|
+
}
|
187
311
|
},
|
188
312
|
'description' => 'This gets Things.'
|
189
|
-
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
190
316
|
end
|
191
317
|
|
192
318
|
let(:http_verbs) { %w(get post put delete) }
|