swagger-doc-rails 1.0.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.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Appraisals +7 -0
  4. data/CHANGELOG.md +120 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +448 -0
  8. data/Rakefile +10 -0
  9. data/certs/gem-public_cert.pem +21 -0
  10. data/lib/swagger/docs.rb +14 -0
  11. data/lib/swagger/docs/api_declaration_file.rb +125 -0
  12. data/lib/swagger/docs/api_declaration_file_metadata.rb +22 -0
  13. data/lib/swagger/docs/config.rb +63 -0
  14. data/lib/swagger/docs/dsl.rb +119 -0
  15. data/lib/swagger/docs/generator.rb +327 -0
  16. data/lib/swagger/docs/impotent_methods.rb +24 -0
  17. data/lib/swagger/docs/methods.rb +52 -0
  18. data/lib/swagger/docs/task.rb +9 -0
  19. data/lib/swagger/docs/version.rb +5 -0
  20. data/lib/tasks/swagger.rake +10 -0
  21. data/spec/fixtures/controllers/application_controller.rb +4 -0
  22. data/spec/fixtures/controllers/custom_resource_path_controller.rb +18 -0
  23. data/spec/fixtures/controllers/ignored_controller.rb +6 -0
  24. data/spec/fixtures/controllers/multiple_routes_controller.rb +13 -0
  25. data/spec/fixtures/controllers/nested_controller.rb +18 -0
  26. data/spec/fixtures/controllers/sample_controller.rb +81 -0
  27. data/spec/lib/swagger/docs/api_declaration_file_metadata_spec.rb +48 -0
  28. data/spec/lib/swagger/docs/api_declaration_file_spec.rb +203 -0
  29. data/spec/lib/swagger/docs/config_spec.rb +48 -0
  30. data/spec/lib/swagger/docs/dsl_spec.rb +17 -0
  31. data/spec/lib/swagger/docs/generator_spec.rb +451 -0
  32. data/spec/lib/swagger/docs/methods.rb +15 -0
  33. data/spec/spec_helper.rb +56 -0
  34. data/swagger-doc-rails.gemspec +31 -0
  35. metadata +175 -0
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Swagger::Docs::Config do
4
+
5
+ require "fixtures/controllers/application_controller"
6
+
7
+ let(:test_controller) { Class.new }
8
+
9
+ before(:each) do
10
+ stub_const('ActionController::Base', ApplicationController)
11
+ end
12
+
13
+ subject { Swagger::Docs::Config }
14
+
15
+ describe "::base_api_controller" do
16
+ it "returns ActionController::Base by default" do
17
+ expect(subject.base_api_controller).to eq(ActionController::Base)
18
+ end
19
+ it "allows assignment of another class" do
20
+ subject.base_api_controller = test_controller
21
+ expect(subject.base_api_controller).to eq(test_controller)
22
+ end
23
+ end
24
+
25
+ describe "::base_api_controllers" do
26
+ it "returns an array with ActionController::Base by default" do
27
+ expect(subject.base_api_controllers).to eq([ActionController::Base])
28
+ end
29
+ it "allows assignment of multiple classes" do
30
+ subject.base_api_controllers = [test_controller, ActionController::Base]
31
+ expect(subject.base_api_controllers).to eq([test_controller, ActionController::Base])
32
+ end
33
+ end
34
+
35
+ describe "::base_application" do
36
+ it "defaults to Rails.application" do
37
+ expect(subject.base_application).to eq (Rails.application)
38
+ end
39
+ end
40
+
41
+ describe "::base_applications" do
42
+ before(:each) { allow( subject ).to receive(:base_application).and_return(:app) }
43
+ it "defaults to Rails.application an an Array" do
44
+ expect(subject.base_applications).to eq [:app]
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Swagger::Docs::SwaggerDSL do
4
+ subject { described_class.new() }
5
+
6
+ describe "#response" do
7
+ it "adds code, responseModel and message to response_messages" do
8
+ subject.response(:ok, "Some sample text", "Tag")
9
+ expect(subject.response_messages).to eq([{:code=>200, :responseModel=>"Tag", :message=>"Some sample text"}])
10
+ end
11
+
12
+ it "accept :success was an :ok status" do
13
+ subject.response(:success, "Some sample text", "Tag")
14
+ expect(subject.response_messages).to eq([{:code=>200, :responseModel=>"Tag", :message=>"Some sample text"}])
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,451 @@
1
+ require 'spec_helper'
2
+
3
+ describe Swagger::Docs::Generator do
4
+
5
+ require "fixtures/controllers/application_controller"
6
+ require "fixtures/controllers/ignored_controller"
7
+
8
+ before(:each) do
9
+ FileUtils.rm_rf(tmp_dir)
10
+ stub_const('ActionController::Base', ApplicationController)
11
+ end
12
+
13
+ let(:routes) {[
14
+ stub_route( "^GET$", "index", "api/v1/ignored", "/api/v1/ignored(.:format)"),
15
+ stub_route( "^GET$", "index", "api/v1/sample", "/api/v1/sample(.:format)"),
16
+ stub_string_verb_route("GET", "index", "api/v1/nested", "/api/v1/nested/:nested_id/nested_sample(.:format)"),
17
+ stub_string_verb_route("GET", "index", "api/v1/custom_resource_path", "/api/v1/custom_resource_path/:custom_resource_path/custom_resource_path_sample(.:format)"),
18
+ stub_route( "^PATCH$", "create", "api/v1/sample", "/api/v1/sample(.:format)"),
19
+ stub_route( "^PUT$", "create", "api/v1/sample", "/api/v1/sample(.:format)"), # intentional duplicate of above route to ensure PATCH is used
20
+ stub_route( "^GET$", "show", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
21
+ stub_route( "^PUT$", "update", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
22
+ stub_route( "^DELETE$", "destroy", "api/v1/sample", "/api/v1/sample/:id(.:format)"),
23
+ stub_route( "^GET$", "new", "api/v1/sample", "/api/v1/sample/new(.:format)"), # no parameters for this method
24
+ stub_route( "^GET$", "index", "", "/api/v1/empty_path"), # intentional empty path should not cause any errors
25
+ stub_route( "^GET$", "ignored", "api/v1/sample", "/api/v1/ignored(.:format)"), # an action without documentation should not cause any errors
26
+ stub_route( "^GET|POST$","index", "api/v1/multiple_routes", "/api/v1/multiple_routes(.:format)") # multiple route methods
27
+ ]}
28
+
29
+ let(:tmp_dir) { Pathname.new('/tmp/swagger-docs/') }
30
+ let(:file_resources) { tmp_dir + 'api-docs.json' }
31
+ let(:file_resource) { tmp_dir + 'api/v1/sample.json' }
32
+ let(:file_resource_nested) { tmp_dir + 'nested.json' }
33
+ let(:file_resource_custom_resource_path) { tmp_dir + 'custom_resource_path.json' }
34
+
35
+ let(:default_config) {
36
+ {
37
+ :controller_base_path => "api/v1",
38
+ :api_file_path => "#{tmp_dir}",
39
+ :base_path => "http://api.no.where/",
40
+ :attributes => {
41
+ :info => {
42
+ "title" => "Swagger Sample App",
43
+ "description" => "This is a sample description.",
44
+ "termsOfServiceUrl" => "http://helloreverb.com/terms/",
45
+ "contact" => "apiteam@wordnik.com",
46
+ "license" => "Apache 2.0",
47
+ "licenseUrl" => "http://www.apache.org/licenses/LICENSE-2.0.html"
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ let(:controllers) { [
54
+ "fixtures/controllers/sample_controller",
55
+ "fixtures/controllers/nested_controller",
56
+ "fixtures/controllers/custom_resource_path_controller",
57
+ "fixtures/controllers/multiple_routes_controller"
58
+ ]}
59
+
60
+ context "without controller base path" do
61
+ let(:config) {
62
+ {
63
+ DEFAULT_VER => {:api_file_path => "#{tmp_dir}", :base_path => "http://api.no.where/"}
64
+ }
65
+ }
66
+ before(:each) do
67
+ allow(Rails).to receive_message_chain(:application, :routes, :routes).and_return(routes)
68
+ Swagger::Docs::Generator.set_real_methods
69
+ require "fixtures/controllers/sample_controller"
70
+ generate(config)
71
+ end
72
+ context "resources files" do
73
+ let(:resources) { file_resources.read }
74
+ let(:response) { JSON.parse(resources) }
75
+ it "writes basePath correctly" do
76
+ expect(response["basePath"]).to eq "http://api.no.where"
77
+ end
78
+ it "writes apis correctly" do
79
+ expect(response["apis"].count).to eq 1
80
+ end
81
+ it "writes api path correctly" do
82
+ expect(response["apis"][0]["path"]).to eq "/api/v1/sample.{format}"
83
+ end
84
+
85
+ context "api_file_name" do
86
+ let(:api_file_name) { 'swagger-docs.json' }
87
+ let(:config) {{
88
+ DEFAULT_VER => {
89
+ :api_file_path => tmp_dir,
90
+ :api_file_name => api_file_name }
91
+ }}
92
+ let(:file_resources) { tmp_dir + api_file_name }
93
+ specify { expect(File.exists? file_resources).to be true }
94
+ end
95
+ end
96
+ context "resource file" do
97
+ let(:resource) { file_resource.read }
98
+ let(:response) { JSON.parse(resource) }
99
+ let(:first) { response["apis"].first }
100
+ let(:operations) { first["operations"] }
101
+ # {"apiVersion":"1.0","swaggerVersion":"1.2","basePath":"/api/v1","resourcePath":"/sample"
102
+ it "writes basePath correctly" do
103
+ expect(response["basePath"]).to eq "http://api.no.where"
104
+ end
105
+ it "writes resourcePath correctly" do
106
+ expect(response["resourcePath"]).to eq "sample"
107
+ end
108
+ it "writes out expected api count" do
109
+ expect(response["apis"].count).to eq 6
110
+ end
111
+ context "first api" do
112
+ #"apis":[{"path":" /sample","operations":[{"summary":"Fetches all User items"
113
+ #,"method":"get","nickname":"Api::V1::Sample#index"}]
114
+ it "writes path correctly" do
115
+ expect(first["path"]).to eq "/api/v1/sample"
116
+ end
117
+ end
118
+ end
119
+ end
120
+ context "with controller base path" do
121
+ let(:config) { Swagger::Docs::Config.register_apis({DEFAULT_VER => default_config})}
122
+ let(:file_resource) { tmp_dir + 'sample.json' }
123
+ let(:resource) { file_resource.read }
124
+ let(:response) { JSON.parse(resource) }
125
+ let(:apis) { response["apis"] }
126
+ before(:each) do
127
+ allow(Rails).to receive_message_chain(:application, :routes, :routes).and_return(routes)
128
+ Swagger::Docs::Generator.set_real_methods
129
+ controllers.each{ |path| require path }
130
+ end
131
+ context "test suite initialization" do
132
+ it "the resources file does not exist" do
133
+ expect(file_resource).to_not exist
134
+ end
135
+ it "the resource file does not exist" do
136
+ expect(file_resource).to_not exist
137
+ end
138
+ end
139
+ describe "#generate" do
140
+ it "respects parent_controller config option" do
141
+ new_config = default_config
142
+ new_config[:parent_controller] = ApplicationController
143
+ api_config = Swagger::Docs::Config.register_apis(DEFAULT_VER => new_config)
144
+ results = generate(api_config)
145
+ expect(results[DEFAULT_VER][:processed].count).to eq(controllers.count)
146
+ end
147
+ end
148
+ describe "#write_docs" do
149
+ context "no apis registered" do
150
+ before(:each) do
151
+ Swagger::Docs::Config.register_apis({})
152
+ end
153
+ it "generates using default config" do
154
+ results = generate({})
155
+ expect(results[DEFAULT_VER][:processed].count).to eq(controllers.count)
156
+ end
157
+ end
158
+ before(:each) do
159
+ generate(config)
160
+ end
161
+ context "api-docs resources file" do
162
+ it "writes the file" do
163
+ expect(file_resources).to exist
164
+ end
165
+ context "custom user attributes" do
166
+ let(:parsed_resources) {
167
+ JSON.parse(File.read file_resources)
168
+ }
169
+ it "it has info hash" do
170
+ expect(parsed_resources.keys).to include("info")
171
+ end
172
+ it "has title field" do
173
+ expect(parsed_resources["info"]["title"]).to eq "Swagger Sample App"
174
+ end
175
+ it "has description field" do
176
+ expect(parsed_resources["info"]["description"]).to eq "This is a sample description."
177
+ end
178
+ end
179
+ end
180
+ it "cleans json files in directory when set" do
181
+ file_to_delete = Pathname.new(File.join(config['1.0'][:api_file_path], 'delete_me.json'))
182
+ File.open(file_to_delete, 'w') {|f| f.write("{}") }
183
+ expect(file_to_delete).to exist
184
+ config[DEFAULT_VER][:clean_directory] = true
185
+ generate(config)
186
+ expect(file_to_delete).to_not exist
187
+ end
188
+ it "keeps non json files in directory when cleaning" do
189
+ file_to_keep = Pathname.new(File.join(config['1.0'][:api_file_path], 'keep_me'))
190
+ File.open(file_to_keep, 'w') {|f| f.write("{}") }
191
+ config[DEFAULT_VER][:clean_directory] = true
192
+ generate(config)
193
+ expect(file_to_keep).to exist
194
+ end
195
+ it "writes the resource file" do
196
+ expect(file_resource).to exist
197
+ end
198
+ it "returns results hash" do
199
+ results = generate(config)
200
+ expect(results[DEFAULT_VER][:processed].count).to eq(controllers.count)
201
+ expect(results[DEFAULT_VER][:skipped].count).to eq 1
202
+ end
203
+ it "writes pretty json files when set" do
204
+ config[DEFAULT_VER][:formatting] = :pretty
205
+ generate(config)
206
+ resources = File.read file_resources
207
+ expect(resources.scan(/\n/).length).to be > 1
208
+ end
209
+ context "resources files" do
210
+ let(:resources) { file_resources.read }
211
+ let(:response) { JSON.parse(resources) }
212
+ it "writes version correctly" do
213
+ expect(response["apiVersion"]).to eq DEFAULT_VER
214
+ end
215
+ it "writes swaggerVersion correctly" do
216
+ expect(response["swaggerVersion"]).to eq "1.2"
217
+ end
218
+ it "writes basePath correctly" do
219
+ expect(response["basePath"]).to eq "http://api.no.where/api/v1"
220
+ end
221
+ it "writes apis correctly" do
222
+ expect(response["apis"].count).to eq(controllers.count)
223
+ end
224
+ it "writes api path correctly" do
225
+ expect(response["apis"][0]["path"]).to eq "/sample.{format}"
226
+ end
227
+ it "writes api description correctly" do
228
+ expect(response["apis"][0]["description"]).to eq "User Management"
229
+ end
230
+ end
231
+ context "nested resource file" do
232
+ let(:resource) { file_resource_nested.read }
233
+ let(:response) { JSON.parse(resource) }
234
+ let(:apis) { response["apis"] }
235
+ context "apis" do
236
+ context "show" do
237
+ let(:api) { get_api_operation(apis, "/nested/{nested_id}/nested_sample", :get) }
238
+ let(:operations) { get_api_operations(apis, "/nested/{nested_id}/nested_sample") }
239
+ context "parameters" do
240
+ it "has correct count" do
241
+ expect(api["parameters"].count).to eq 2
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end
247
+ context "multiple routes resource file" do
248
+ let(:file_resource) { tmp_dir + 'multiple_routes.json' }
249
+ it "handles multiple GET path" do
250
+ resource = get_api_operation(apis, "/multiple_routes", :get)
251
+ expect(resource["method"]).to eq "get"
252
+ end
253
+ it "handles multiple POST path" do
254
+ resource = get_api_operation(apis, "/multiple_routes", :post)
255
+ expect(resource["method"]).to eq "post"
256
+ end
257
+ end
258
+ context "sample resource file" do
259
+ # {"apiVersion":"1.0","swaggerVersion":"1.2","basePath":"/api/v1","resourcePath":"/sample"
260
+ it "writes version correctly" do
261
+ expect(response["apiVersion"]).to eq DEFAULT_VER
262
+ end
263
+ it "writes swaggerVersion correctly" do
264
+ expect(response["swaggerVersion"]).to eq "1.2"
265
+ end
266
+ it "writes basePath correctly" do
267
+ expect(response["basePath"]).to eq "http://api.no.where/api/v1"
268
+ end
269
+ it "writes resourcePath correctly" do
270
+ expect(response["resourcePath"]).to eq "sample"
271
+ end
272
+ it "writes out expected api count" do
273
+ expect(response["apis"].count).to eq 6
274
+ end
275
+ describe "context dependent documentation" do
276
+ after(:each) do
277
+ ApplicationController.context = "original"
278
+ end
279
+ let(:routes) {[stub_route("^GET$", "context_dependent", "api/v1/sample", "/api/v1/sample(.:format)")]}
280
+ let(:operations) { apis[0]["operations"] }
281
+ it "should be the original" do
282
+ ApplicationController.context = "original"
283
+ generate(config)
284
+ expect(operations.first["summary"]).to eq "An action dependent on the context of the controller class. Right now it is: original"
285
+ end
286
+ context "when modified" do
287
+ it "should be modified" do
288
+ ApplicationController.context = "modified"
289
+ generate(config)
290
+ expect(operations.first["summary"]).to eq "An action dependent on the context of the controller class. Right now it is: modified"
291
+ end
292
+ end
293
+ end
294
+ context "apis" do
295
+ context "index" do
296
+ let(:api) { get_api_operation(apis, "/sample", :get) }
297
+ let(:operations) { get_api_operations(apis, "/sample") }
298
+ #"apis":[{"path":" /sample","operations":[{"summary":"Fetches all User items"
299
+ #,"method":"get","nickname":"Api::V1::Sample#index"}]
300
+ it "writes path correctly when api extension type is not set" do
301
+ expect(apis.first["path"]).to eq "/sample"
302
+ end
303
+ it "writes path correctly when api extension type is set" do
304
+ config[DEFAULT_VER][:api_extension_type] = :json
305
+ generate(config)
306
+ expect(apis.first["path"]).to eq "/sample.json"
307
+ end
308
+ it "writes summary correctly" do
309
+ expect(operations.first["summary"]).to eq "Fetches all User items"
310
+ end
311
+ it "writes method correctly" do
312
+ expect(operations.first["method"]).to eq "get"
313
+ end
314
+ it "writes nickname correctly" do
315
+ expect(operations.first["nickname"]).to eq "Api::V1::Sample#index"
316
+ end
317
+ it "writes responseModel attribute" do
318
+ expect(api["responseMessages"].find{|m| m["responseModel"] == "Tag"}).to_not be_nil
319
+ end
320
+ it "writes response code as 200" do
321
+ expect(api["responseMessages"].find{|m| m["responseModel"] == "Tag"}["code"]).to eq 200
322
+ end
323
+ #"parameters"=>[
324
+ # {"paramType"=>"query", "name"=>"page", "type"=>"integer", "description"=>"Page number", "required"=>false},
325
+ # {"paramType"=>"path", "name"=>"nested_id", "type"=>"integer", "description"=>"Team Id", "required"=>false}], "responseMessages"=>[{"code"=>401, "message"=>"Unauthorized"}, {"code"=>406, "message"=>"The request you made is not acceptable"}, {"code"=>416, "message"=>"Requested Range Not Satisfiable"}], "method"=>"get", "nickname"=>"Api::V1::Sample#index"}
326
+ #]
327
+ context "parameters" do
328
+ let(:params) { operations.first["parameters"] }
329
+ it "has correct count" do
330
+ expect(params.count).to eq 1
331
+ end
332
+ it "writes paramType correctly" do
333
+ expect(params.first["paramType"]).to eq "query"
334
+ end
335
+ it "writes name correctly" do
336
+ expect(params.first["name"]).to eq "page"
337
+ end
338
+ it "writes type correctly" do
339
+ expect(params.first["type"]).to eq "integer"
340
+ end
341
+ it "writes description correctly" do
342
+ expect(params.first["description"]).to eq "Page number"
343
+ end
344
+ it "writes required correctly" do
345
+ expect(params.first["required"]).to be_falsey
346
+ end
347
+ end
348
+ context "list parameter" do
349
+ let(:api) { get_api_operation(apis, "/sample", :patch) }
350
+ let(:params) {api["parameters"] }
351
+ it "writes description correctly" do
352
+ expect(params[3]["description"]).to eq "Role"
353
+ end
354
+ end
355
+ #"responseMessages":[{"code":401,"message":"Unauthorized"},{"code":406,"message":"Not Acceptable"},{"code":416,"message":"Requested Range Not Satisfiable"}]
356
+ context "response messages" do
357
+ let(:response_msgs) { operations.first["responseMessages"] }
358
+ it "has correct count" do
359
+ expect(response_msgs.count).to eq 4
360
+ end
361
+ it "writes code correctly" do
362
+ expect(response_msgs.first["code"]).to eq 200
363
+ end
364
+ it "writes message correctly" do
365
+ expect(response_msgs.first["message"]).to eq "Some text"
366
+ end
367
+ it "writes specified message correctly" do
368
+ expect(response_msgs[1]["message"]).to eq "Unauthorized"
369
+ end
370
+ end
371
+ end
372
+ context "create" do
373
+ let(:api) { get_api_operation(apis, "/sample", :patch) }
374
+ it "writes list parameter values correctly" do
375
+ expected_param = {"valueType"=>"LIST", "values"=>["admin", "superadmin", "user"]}
376
+ expected_body = {"paramType"=>"body", "name"=>"body", "type"=>"json", "description"=>"JSON formatted body", "required"=>true}
377
+ expected_consumes = ["application/json", "text/xml"]
378
+ expect(get_api_parameter(api, "role")["allowableValues"]).to eq expected_param
379
+ expect(get_api_parameter(api, "body")).to eq expected_body
380
+ expect(api["consumes"]).to eq ["application/json", "text/xml"]
381
+ expect(api["items"]).to eq("{$ref\" => \"setup\"}")
382
+ end
383
+ it "doesn't write out route put method" do
384
+ expect(get_api_operation(apis, "sample", :put)).to be_nil
385
+ end
386
+ end
387
+ context "update" do
388
+ let(:api) { get_api_operation(apis, "/sample/{id}", :put) }
389
+ it "writes notes correctly" do
390
+ expect(api["notes"]).to eq "Only the given fields are updated."
391
+ end
392
+ it "writes model param correctly" do
393
+ expected_param = {
394
+ "paramType" => "form",
395
+ "name" => "tag",
396
+ "type" => "Tag",
397
+ "description" => "Tag object",
398
+ "required" => true,
399
+ }
400
+ expect(get_api_parameter(api, "tag")).to eq expected_param
401
+ end
402
+ end
403
+ end
404
+ context "models" do
405
+ let(:models) { response["models"] }
406
+ # Based on https://github.com/wordnik/swagger-core/wiki/Datatypes
407
+ it "writes model correctly" do
408
+ expected_model = {
409
+ "id" => "Tag",
410
+ "required" => ["id"],
411
+ "description" => "A Tag object.",
412
+ "properties" => {
413
+ "name" => {
414
+ "type" => "string",
415
+ "description" => "Name",
416
+ "foo" => "test",
417
+ },
418
+ "id" => {
419
+ "type" => "integer",
420
+ "description" => "User Id",
421
+ },
422
+ "type" => {
423
+ "type" => "string",
424
+ "description" => "Type",
425
+ "allowableValues" => {
426
+ "valueType" => "LIST",
427
+ "values" => [
428
+ "info",
429
+ "warning",
430
+ "error"
431
+ ]
432
+ }
433
+ }
434
+ }
435
+ }
436
+ expect(models['Tag']).to eq expected_model
437
+ end
438
+ end
439
+ context "custom resource_path resource file" do
440
+ let(:resource) { file_resource_custom_resource_path.read }
441
+ let(:response) { JSON.parse(resource) }
442
+ let(:apis) { response["apis"] }
443
+ # {"apiVersion":"1.0","swaggerVersion":"1.2","basePath":"/api/v1","resourcePath":"/sample"
444
+ it "writes resourcePath correctly" do
445
+ expect(response["resourcePath"]).to eq "resource/testing"
446
+ end
447
+ end
448
+ end
449
+ end
450
+ end
451
+ end