apipie-rails 0.5.7 → 0.5.8

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.
@@ -0,0 +1,73 @@
1
+ #
2
+ # demonstration of how the 'describe_own_properties' method can be used
3
+ # to integrate Apipie response descriptions with view generation packages
4
+ # such as, for example, Grape::Entity
5
+ #
6
+
7
+ # Consider a hypothetical SelfDocumentingView class (a stand-in for Grape::Entity
8
+ # for demonstrational purposes). This is an abstract class, supporting the implementation
9
+ # of actual views as subclasses of SelfDocumentingView.
10
+ #
11
+ # A user of SelfDocumentingView would implement a subclass for each desired view. Each such
12
+ # view definition would include, for each field that should be returned in the JSON response,
13
+ # an instance method called v_<name>__<type>.
14
+ #
15
+ # SelfDocumentingView would then scan the subclass for such fields and:
16
+ # 1. Given an id: fetch the matching model and generated a view from it using the field definitions
17
+ # 2. Describe the structure of such views to Apipie using self.describe_own_properties
18
+ #
19
+ # (see the controller implementation below for how such a class might be used)
20
+
21
+ class SelfDocumentingView
22
+ # self.describe_own_properties (a class method) generates the meta-data
23
+ # (i.e., the type description) for the subclass.
24
+ def self.describe_own_properties
25
+ (self.instance_methods - self.class.instance_methods).map{|m|
26
+ if matchdata = /^v_(\w+)__(\w+)$/.match(m)
27
+ Apipie::prop(matchdata[1], matchdata[2])
28
+ end
29
+ }.compact
30
+ end
31
+
32
+ # to_json (an instance method) generates the actual view
33
+ def to_json
34
+ { note: "in an actual implementation of SelfDocumentingView, this method
35
+ would call each v_<name>__<type> method and include its output
36
+ in the response as a (<name>: <value>) pair"
37
+ }
38
+ end
39
+
40
+ def initialize(id)
41
+ load_from_model(id)
42
+ end
43
+
44
+ def load_from_model(id)
45
+ # in a real implementation of SelfDocumentingView, this
46
+ # method would load the fields to be displayed from the model
47
+ # instance identified by 'id'
48
+ end
49
+ end
50
+
51
+
52
+ #
53
+ # ViewOfPet extends SelfDocumentingView to include specific fields
54
+ #
55
+ class ViewOfPet < SelfDocumentingView
56
+ attr_accessor :v_pet_name__string
57
+ attr_accessor :v_animal_type__string
58
+ attr_accessor :v_age__number
59
+ end
60
+
61
+
62
+ class PetsUsingAutoViewsController < ApplicationController
63
+ #-----------------------------------------------------------
64
+ # Method returning an array of AutomatedViewOfPet (where
65
+ # AutomatedViewOfPet is an auto-generated self-describing class)
66
+ # -----------------------------------------------------------
67
+ api :GET, "/pet_described_using_automated_view/:id", "Get the measurements of a single pet"
68
+ param :id, String
69
+ returns ViewOfPet, :desc => "like Pet, but different"
70
+ def pet_described_using_automated_view
71
+ render :plain => ViewOfPet.new(params.id).to_json
72
+ end
73
+ end
@@ -0,0 +1,95 @@
1
+ #----------------------------------------------------------------------------------------------------
2
+ # A "self-describing class" is a class that respond_to? :describe_own_properties
3
+ # and returns an array of Property Descriptions.
4
+ # (The simple way to create Property Description objects is using the Apipie::prop helper function,
5
+ # which is a factory for Apipie::ResponseDescriptionAdapter::PropDesc instances)
6
+ #
7
+ #----------------------------------------------------------------------------------------------------
8
+
9
+
10
+ # in this example, Pet is a self-describing class with only two properties.
11
+ # In a real implementation, the Pet class would actually do something with these properties.
12
+ # Here, the class is defined to only include the describe_own_properties method.
13
+ class Pet
14
+ def self.describe_own_properties
15
+ [
16
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
17
+ Apipie::prop(:animal_type, 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
18
+ Apipie::additional_properties(false)
19
+ ]
20
+ end
21
+ end
22
+
23
+ #
24
+ # PetWithMeasurements is a self-describing class with an embedded object
25
+ #
26
+ class PetWithMeasurements
27
+ def self.describe_own_properties
28
+ [
29
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
30
+ Apipie::prop('animal_type', 'string', {:description => 'Type of pet', :values => ["dog", "cat", "iguana", "kangaroo"]}),
31
+ Apipie::prop(:pet_measurements, 'object', {}, [
32
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
33
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
34
+ Apipie::prop(:num_legs, 'number', {:description => "Number of legs", :required => false }),
35
+ Apipie::additional_properties(false)
36
+ ])
37
+ ]
38
+ end
39
+ end
40
+
41
+ #
42
+ # PetWithManyMeasurements is a self-describing class with an embedded object
43
+ #
44
+ class PetWithManyMeasurements
45
+ def self.describe_own_properties
46
+ [
47
+ Apipie::prop(:pet_name, 'string', {:description => 'Name of pet', :required => false}),
48
+ Apipie::prop(:many_pet_measurements, 'object', {is_array: true}, [
49
+ Apipie::prop(:weight, 'number', {:description => "Weight in pounds" }),
50
+ Apipie::prop(:height, 'number', {:description => "Height in inches" }),
51
+ ])
52
+ ]
53
+ end
54
+ end
55
+
56
+
57
+
58
+ class PetsUsingSelfDescribingClassesController < ApplicationController
59
+ resource_description do
60
+ description 'A controller to test "returns" using self-describing classes'
61
+ short 'Pets'
62
+ path '/pets2'
63
+ end
64
+
65
+ #-----------------------------------------------------------
66
+ # Method returning an array of Pet (a self-describing class)
67
+ # -----------------------------------------------------------
68
+ api :GET, "/pets_described_as_class", "Get all pets"
69
+ returns :array_of => Pet, :desc => "list of pets"
70
+ def pets_described_as_class
71
+ render :plain => "all pets"
72
+ end
73
+
74
+ #-----------------------------------------------------------
75
+ # Method returning an array of PetWithMeasurements (a self-describing class)
76
+ # -----------------------------------------------------------
77
+ api :GET, "/pets_with_measurements_described_as_class/:id", "Get the measurements of a single pet"
78
+ param :id, String
79
+ returns PetWithMeasurements, :desc => "measurements of the pet"
80
+ def pets_with_measurements_described_as_class
81
+ render :plain => "all pets"
82
+ end
83
+
84
+ #-----------------------------------------------------------
85
+ # Method returning an array of PetWithManyMeasurements (a self-describing class with array field)
86
+ # -----------------------------------------------------------
87
+ api :GET, "/pets_with_many_measurements_as_class/:id", "Get the measurements of a single pet"
88
+ param :id, String
89
+ returns PetWithManyMeasurements, :desc => "measurements of the pet"
90
+ def pets_with_many_measurements_as_class
91
+ render :plain => "all pets"
92
+ end
93
+
94
+ end
95
+
@@ -57,10 +57,38 @@ describe Apipie::Extractor::Writer do
57
57
  }
58
58
  }
59
59
 
60
- describe "with doc_path overriden in configuration" do
61
- it "should use the doc_path specified in configuration" do
62
- Apipie.configuration.doc_path = "user_specified_doc_path"
63
- expect(writer_class.examples_file).to eql(File.join(Rails.root, "user_specified_doc_path", "apipie_examples.json"))
60
+ context 'with doc_path overriden in configuration' do
61
+ around(:each) do |example|
62
+ standard_path = Apipie.configuration.doc_path
63
+ Apipie.configuration.doc_path = 'user_specified_doc_path'
64
+ example.run
65
+ Apipie.configuration.doc_path = standard_path
66
+ end
67
+
68
+ it 'should use the doc_path specified in configuration' do
69
+ expect(writer_class.examples_file).to eql(File.join(Rails.root, 'user_specified_doc_path', 'apipie_examples.json'))
70
+ end
71
+ end
72
+
73
+ context 'when compressing examples' do
74
+ around(:each) do |example|
75
+ Apipie.configuration.compress_examples = true
76
+ example.run
77
+ FileUtils.rm(writer_class.examples_file) if File.exist?(writer_class.examples_file)
78
+ Apipie.configuration.compress_examples = nil
79
+ end
80
+
81
+ it 'should write to a compressed file' do
82
+ expect(writer_class.examples_file).to match(/\.gz$/)
83
+ writer_class.write_recorded_examples(records)
84
+ expect(File.exist?(writer_class.examples_file))
85
+ end
86
+
87
+ it 'should read from a compressed file' do
88
+ writer_class.write_recorded_examples(records)
89
+ expected_string = writer_class.send(:serialize_examples, records)
90
+ expect(writer_class.load_recorded_examples)
91
+ .to eql(writer_class.send(:deserialize_examples, expected_string))
64
92
  end
65
93
  end
66
94
 
@@ -68,4 +68,31 @@ describe Apipie::MethodDescription do
68
68
 
69
69
  end
70
70
 
71
+ describe "response-only properties" do
72
+ before(:each) do
73
+ @resource = Apipie::ResourceDescription.new(ApplicationController, "dummy")
74
+ dsl_data[:params] = [[:a, String, nil, {:only_in => :request}, nil],
75
+ [:b, String, nil, {:only_in => :response}, nil],
76
+ [:c, String, nil, {}, nil]]
77
+ @method = Apipie::MethodDescription.new(:a, @resource, dsl_data)
78
+ @resource.add_method_description @method
79
+ end
80
+
81
+ it "should ignore response-only parameters" do
82
+ expect(@method.params.keys).to eq([:a, :c])
83
+ expect(@method.to_json[:params].map{|h| h[:name]}).to eq(['a', 'c'])
84
+ end
85
+ end
86
+
87
+
88
+ describe "'returns' properties" do
89
+ it "should raise an error if both :param_group and :array_of are specified in 'returns'" do
90
+ @resource = Apipie::ResourceDescription.new(ApplicationController, "dummy")
91
+ dsl_data[:returns] = { 200 => [{:param_group => 'pet', :array_of => 'pet'}, nil, nil] }
92
+
93
+ expect {Apipie::MethodDescription.new(:a, @resource, dsl_data)}.to raise_error(Apipie::ReturnsMultipleDefinitionError)
94
+ end
95
+ end
96
+
97
+
71
98
  end
@@ -1,6 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require "json-schema"
3
3
 
4
+ require File.expand_path("../../../dummy/app/controllers/twitter_example_controller.rb", __FILE__)
5
+ require File.expand_path("../../../dummy/app/controllers/users_controller.rb", __FILE__)
6
+ require File.expand_path("../../../dummy/app/controllers/pets_controller.rb", __FILE__)
7
+
4
8
  describe 'rake tasks' do
5
9
  include_context "rake"
6
10
 
@@ -0,0 +1,489 @@
1
+ require 'spec_helper'
2
+ require 'rack/utils'
3
+ require 'rspec/expectations'
4
+
5
+ describe "Swagger Responses" do
6
+ let(:desc) { Apipie.get_resource_description(controller_class, Apipie.configuration.default_version) }
7
+
8
+ let(:swagger) {
9
+ Apipie.configuration.swagger_suppress_warnings = true
10
+ Apipie.to_swagger_json(Apipie.configuration.default_version, controller_class.to_s.underscore.sub("_controller", ""))
11
+ }
12
+
13
+ let(:controller_class ) { described_class }
14
+
15
+ def swagger_response_for(path, code=200, method='get')
16
+ swagger[:paths][path][method][:responses][code]
17
+ end
18
+
19
+ def swagger_params_for(path, method='get')
20
+ swagger[:paths][path][method][:parameters]
21
+ end
22
+
23
+ def swagger_param_by_name(param_name, path, method='get')
24
+ params = swagger_params_for(path, method)
25
+ matching = params.select{|p| p[:name] == param_name }
26
+ raise "multiple params named [#{param_name}] in swagger definition for [#{method } #{path}]" if matching.length > 1
27
+
28
+ nil if matching.length == 0
29
+
30
+ matching[0]
31
+ end
32
+
33
+
34
+
35
+ describe PetsController do
36
+
37
+
38
+ describe "PetsController#index" do
39
+ subject do
40
+ desc._methods[:index]
41
+ end
42
+
43
+ it "should return code 200 with array of entries of the format {'pet_name', 'animal_type'}" do
44
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
45
+
46
+ puts returns_obj.to_json
47
+ expect(returns_obj.code).to eq(200)
48
+ expect(returns_obj.is_array?).to eq(true)
49
+
50
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type])
51
+ end
52
+
53
+ it 'should have the response described in the swagger' do
54
+ response = swagger_response_for('/pets')
55
+ expect(response[:description]).to eq("list of pets")
56
+
57
+ schema = response[:schema]
58
+ expect(schema[:type]).to eq("array")
59
+
60
+ a_schema = schema[:items]
61
+ expect(a_schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
62
+ expect(a_schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
63
+ end
64
+
65
+
66
+ it "should return code 401 with a String description field" do
67
+ returns_obj = subject.returns.detect{|e| e.code == 404 }
68
+
69
+ expect(returns_obj.code).to eq(404)
70
+ expect(returns_obj.is_array?).to eq(false)
71
+
72
+ expect(returns_obj).to match_field_structure([:error_message])
73
+ end
74
+
75
+
76
+ it "should return code 401 with a :reason field (defined in the superclass)" do
77
+ returns_obj = subject.returns.detect{|e| e.code == 401 }
78
+
79
+ expect(returns_obj.code).to eq(401)
80
+ expect(returns_obj.is_array?).to eq(false)
81
+
82
+ expect(returns_obj).to match_field_structure([:reason])
83
+ end
84
+
85
+ it 'should have the 404 response described in the swagger' do
86
+ response = swagger_response_for('/pets', 404)
87
+ expect(response[:description]).to eq("Not Found")
88
+
89
+ schema = response[:schema]
90
+ expect(schema[:type]).to eq("object")
91
+
92
+ expect(schema).to have_field(:error_message, 'string', {:description => 'description of the error', :required => true})
93
+ end
94
+
95
+ end
96
+
97
+ describe "PetsController#show_as_properties" do
98
+ subject do
99
+ desc._methods[:show_as_properties]
100
+ end
101
+
102
+ it "should return code 200 with 'pet_name' and 'animal_type'" do
103
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
104
+
105
+ puts returns_obj.to_json
106
+ expect(returns_obj.code).to eq(200)
107
+ expect(returns_obj.is_array?).to eq(false)
108
+
109
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type])
110
+ end
111
+
112
+ it 'should have the response described in the swagger' do
113
+ response = swagger_response_for('/pets/{id}/as_properties')
114
+ expect(response[:description]).to eq("OK")
115
+
116
+ schema = response[:schema]
117
+ expect(schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
118
+ expect(schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
119
+ end
120
+
121
+ it 'should have the 404 response description overridden' do
122
+ returns_obj = subject.returns.detect{|e| e.code == 404 }
123
+
124
+ # puts returns_obj.to_json
125
+ expect(returns_obj.code).to eq(404)
126
+ expect(returns_obj.is_array?).to eq(false)
127
+
128
+ expect(returns_obj).to match_field_structure([:another_error_message])
129
+ end
130
+ end
131
+
132
+ describe "PetsController#show_as_param_group_of_properties" do
133
+ subject do
134
+ desc._methods[:show_as_param_group_of_properties]
135
+ end
136
+
137
+ it "should return code 200 with 'pet_name' and 'animal_type'" do
138
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
139
+
140
+ puts returns_obj.to_json
141
+ expect(returns_obj.code).to eq(200)
142
+ expect(returns_obj.is_array?).to eq(false)
143
+
144
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type])
145
+ expect(returns_obj.params_ordered[0].is_required?).to be_falsey
146
+ expect(returns_obj.params_ordered[1].is_required?).to be_truthy
147
+ end
148
+
149
+ it 'should have the response described in the swagger' do
150
+ response = swagger_response_for('/pets/{id}/as_param_group_of_properties')
151
+ expect(response[:description]).to eq("The pet")
152
+
153
+ schema = response[:schema]
154
+ expect(schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
155
+ expect(schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
156
+ end
157
+ end
158
+
159
+ describe "PetsController#show_pet_by_id" do
160
+ subject do
161
+ desc._methods[:show_pet_by_id]
162
+ end
163
+
164
+ it "should have only oauth (from ApplicationController), common_param (from resource) and pet_id as an input parameters" do
165
+ params_obj = subject.params_ordered
166
+
167
+ expect(params_obj[0].name).to eq(:oauth)
168
+ expect(params_obj[1].name).to eq(:common_param)
169
+ expect(params_obj[2].name).to eq(:pet_id)
170
+ end
171
+
172
+ it "should return code 200 with 'pet_id', pet_name' and 'animal_type'" do
173
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
174
+
175
+ puts returns_obj.to_json
176
+ expect(returns_obj.code).to eq(200)
177
+ expect(returns_obj.is_array?).to eq(false)
178
+
179
+ # note that the response is expected NOT to return the parameters marked ':only_in => :request'
180
+ expect(returns_obj).to match_field_structure([:pet_id, :pet_name, :animal_type])
181
+ end
182
+
183
+ it 'should have the response described in the swagger' do
184
+ response = swagger_response_for('/pets/pet_by_id')
185
+ expect(response[:description]).to eq("OK")
186
+
187
+ schema = response[:schema]
188
+ expect(schema).to have_field(:pet_id, 'number', {:description => 'id of pet'})
189
+ expect(schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
190
+ expect(schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
191
+ expect(schema).not_to have_field(:partial_match_allowed, 'boolean', {:required => false})
192
+ end
193
+
194
+ it "creates a swagger definition with all input parameters" do
195
+ # a parameter defined for this method
196
+ expect(swagger_param_by_name(:pet_id, '/pets/pet_by_id')[:type]).to eq('number')
197
+
198
+ # a parameter defined for the resource
199
+ expect(swagger_param_by_name(:common_param, '/pets/pet_by_id')[:type]).to eq('number')
200
+
201
+ # a parameter defined in the controller's superclass
202
+ expect(swagger_param_by_name(:oauth, '/pets/pet_by_id')[:type]).to eq('string')
203
+ end
204
+
205
+ end
206
+
207
+ describe "PetsController#get_vote_by_owner_name" do
208
+ subject do
209
+ desc._methods[:get_vote_by_owner_name]
210
+ end
211
+
212
+ it "should return code 200 with 'owner_name' and 'vote'" do
213
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
214
+
215
+ puts returns_obj.to_json
216
+ expect(returns_obj.code).to eq(200)
217
+ expect(returns_obj.is_array?).to eq(false)
218
+
219
+ expect(returns_obj).to match_field_structure([:owner_name, :vote])
220
+ end
221
+
222
+ it 'should have the response described in the swagger' do
223
+ response = swagger_response_for('/pets/by_owner_name/did_vote')
224
+ expect(response[:description]).to eq("OK")
225
+
226
+ schema = response[:schema]
227
+ expect(schema).to have_field(:owner_name, 'string', {:required => false}) # optional because defined using 'param', not 'property'
228
+ expect(schema).to have_field(:vote, 'boolean')
229
+ end
230
+ end
231
+
232
+ describe "PetsController#show_extra_info" do
233
+ subject do
234
+ desc._methods[:show_extra_info]
235
+ end
236
+
237
+ it "should return code 201 with 'pet_name' and 'animal_type'" do
238
+ returns_obj = subject.returns.detect{|e| e.code == 201 }
239
+
240
+ puts returns_obj.to_json
241
+ expect(returns_obj.code).to eq(201)
242
+ expect(returns_obj.is_array?).to eq(false)
243
+
244
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type])
245
+ end
246
+ it 'should have the 201 response described in the swagger' do
247
+ response = swagger_response_for('/pets/{id}/extra_info', 201)
248
+ expect(response[:description]).to eq("Found a pet")
249
+
250
+ schema = response[:schema]
251
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
252
+ expect(schema).to have_field(:animal_type, 'string')
253
+ end
254
+
255
+ it "should return code 202 with spread out 'pet' and encapsulated 'pet_measurements'" do
256
+ returns_obj = subject.returns.detect{|e| e.code == 202 }
257
+
258
+ puts returns_obj.to_json
259
+ expect(returns_obj.code).to eq(202)
260
+ expect(returns_obj.is_array?).to eq(false)
261
+
262
+ expect(returns_obj).to match_field_structure([:pet_name,
263
+ :animal_type,
264
+ {:pet_measurements => [:weight, :height, :num_legs]}
265
+ ])
266
+ end
267
+ it 'should have the 202 response described in the swagger' do
268
+ response = swagger_response_for('/pets/{id}/extra_info', 202)
269
+ expect(response[:description]).to eq('Accepted')
270
+
271
+ schema = response[:schema]
272
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
273
+ expect(schema).to have_field(:animal_type, 'string')
274
+ expect(schema).to have_field(:pet_measurements, 'object')
275
+
276
+ pm_schema = schema[:properties][:pet_measurements]
277
+ expect(pm_schema).to have_field(:weight, 'number', {:description => "Weight in pounds"})
278
+ expect(pm_schema).to have_field(:height, 'number', {:description => "Height in inches"})
279
+ expect(pm_schema).to have_field(:num_legs, 'number', {:description => "Number of legs", :required => false})
280
+ end
281
+
282
+ it "should return code 203 with spread out 'pet', encapsulated 'pet_measurements' and encapsulated 'pet_history'" do
283
+ returns_obj = subject.returns.detect{|e| e.code == 203 }
284
+
285
+ puts returns_obj.to_json
286
+ expect(returns_obj.code).to eq(203)
287
+ expect(returns_obj.is_array?).to eq(false)
288
+
289
+ expect(returns_obj).to match_field_structure([:pet_name,
290
+ :animal_type,
291
+ {:pet_measurements => [:weight, :height,:num_legs]},
292
+ {:pet_history => [:did_visit_vet, :avg_meals_per_day]},
293
+ {:additional_histories => [:did_visit_vet, :avg_meals_per_day]}
294
+ ])
295
+ end
296
+ it 'should have the 203 response described in the swagger' do
297
+ response = swagger_response_for('/pets/{id}/extra_info', 203)
298
+ expect(response[:description]).to eq('Non-Authoritative Information')
299
+
300
+ schema = response[:schema]
301
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
302
+ expect(schema).to have_field(:animal_type, 'string')
303
+ expect(schema).to have_field(:pet_measurements, 'object')
304
+ expect(schema).to have_field(:pet_history, 'object')
305
+ expect(schema).to have_field(:additional_histories, 'array')
306
+
307
+ pm_schema = schema[:properties][:pet_measurements]
308
+ expect(pm_schema).to have_field(:weight, 'number', {:description => "Weight in pounds"})
309
+ expect(pm_schema).to have_field(:height, 'number', {:description => "Height in inches"})
310
+ expect(pm_schema).to have_field(:num_legs, 'number', {:description => "Number of legs", :required => false})
311
+
312
+ ph_schema = schema[:properties][:pet_history]
313
+ expect(ph_schema).to have_field(:did_visit_vet, 'boolean')
314
+ expect(ph_schema).to have_field(:avg_meals_per_day, 'number')
315
+
316
+ pa_schema = schema[:properties][:additional_histories]
317
+ expect(pa_schema[:type]).to eq('array')
318
+ pai_schema = schema[:properties][:additional_histories][:items]
319
+ expect(pai_schema).to have_field(:did_visit_vet, 'boolean')
320
+ expect(pai_schema).to have_field(:avg_meals_per_day, 'number')
321
+ end
322
+
323
+ it "should return code matching :unprocessable_entity (422) with spread out 'pet' and 'num_fleas'" do
324
+ returns_obj = subject.returns.detect{|e| e.code == 422 }
325
+
326
+ puts returns_obj.to_json
327
+ expect(returns_obj.code).to eq(422)
328
+
329
+ expect(returns_obj).to match_field_structure([:pet_name,
330
+ :animal_type,
331
+ :num_fleas
332
+ ])
333
+ end
334
+ it 'should have the 422 response described in the swagger' do
335
+ response = swagger_response_for('/pets/{id}/extra_info', 422)
336
+ expect(response[:description]).to eq('Fleas were discovered on the pet')
337
+
338
+ schema = response[:schema]
339
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
340
+ expect(schema).to have_field(:animal_type, 'string')
341
+ expect(schema).to have_field(:num_fleas, 'number')
342
+ end
343
+
344
+ end
345
+
346
+ end
347
+
348
+ #==============================================================================
349
+ # PetsUsingSelfDescribingClassesController is a demonstration of how
350
+ # responses can be described using manual generation of a property description
351
+ # array
352
+ #==============================================================================
353
+
354
+
355
+ describe PetsUsingSelfDescribingClassesController do
356
+
357
+ describe "PetsController#pets_described_as_class" do
358
+ subject do
359
+ desc._methods[:pets_described_as_class]
360
+ end
361
+
362
+ it "should return code 200 with array of entries of the format {'pet_name', 'animal_type'}" do
363
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
364
+
365
+ puts returns_obj.to_json
366
+ expect(returns_obj.code).to eq(200)
367
+ expect(returns_obj.is_array?).to eq(true)
368
+
369
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type])
370
+ end
371
+
372
+ it 'should have the response described in the swagger' do
373
+ response = swagger_response_for('/pets_described_as_class')
374
+ expect(response[:description]).to eq("list of pets")
375
+
376
+ schema = response[:schema]
377
+ expect(schema[:type]).to eq("array")
378
+
379
+ a_schema = schema[:items]
380
+ expect(a_schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
381
+ expect(a_schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
382
+ end
383
+ end
384
+
385
+
386
+ describe "PetsController#pets_with_measurements_described_as_class" do
387
+ subject do
388
+ desc._methods[:pets_with_measurements_described_as_class]
389
+ end
390
+
391
+ it "should return code 200 with spread out 'pet' and encapsulated 'pet_measurements'" do
392
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
393
+
394
+ puts returns_obj.to_json
395
+ expect(returns_obj.code).to eq(200)
396
+ expect(returns_obj.is_array?).to eq(false)
397
+
398
+ expect(returns_obj).to match_field_structure([:pet_name,
399
+ :animal_type,
400
+ {:pet_measurements => [:weight, :height, :num_legs]}
401
+ ])
402
+ end
403
+ it 'should have the 200 response described in the swagger' do
404
+ response = swagger_response_for('/pets_with_measurements_described_as_class/{id}', 200)
405
+ expect(response[:description]).to eq('measurements of the pet')
406
+
407
+ schema = response[:schema]
408
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
409
+ expect(schema).to have_field(:animal_type, 'string')
410
+ expect(schema).to have_field(:pet_measurements, 'object')
411
+
412
+ pm_schema = schema[:properties][:pet_measurements]
413
+ expect(pm_schema).to have_field(:weight, 'number', {:description => "Weight in pounds"})
414
+ expect(pm_schema).to have_field(:height, 'number', {:description => "Height in inches"})
415
+ expect(pm_schema).to have_field(:num_legs, 'number', {:description => "Number of legs", :required => false})
416
+ end
417
+ end
418
+
419
+ describe "PetsController#pets_with_many_measurements_as_class" do
420
+ subject do
421
+ desc._methods[:pets_with_many_measurements_as_class]
422
+ end
423
+
424
+ it "should return code 200 with pet_name (string) and many_pet_measurements (array of objects)" do
425
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
426
+
427
+ puts returns_obj.to_json
428
+ expect(returns_obj.code).to eq(200)
429
+ expect(returns_obj.is_array?).to eq(false)
430
+
431
+ expect(returns_obj).to match_field_structure([:pet_name,
432
+ {:many_pet_measurements => [:weight, :height]}
433
+ ])
434
+ end
435
+
436
+
437
+ it 'should have the 200 response described in the swagger' do
438
+ response = swagger_response_for('/pets_with_many_measurements_as_class/{id}', 200)
439
+ expect(response[:description]).to eq('measurements of the pet')
440
+
441
+ schema = response[:schema]
442
+ expect(schema).to have_field(:pet_name, 'string', {:required => false})
443
+ expect(schema).to have_field(:many_pet_measurements, 'array')
444
+
445
+ pm_schema = schema[:properties][:many_pet_measurements][:items]
446
+ expect(pm_schema).to have_field(:weight, 'number', {:description => "Weight in pounds"})
447
+ expect(pm_schema).to have_field(:height, 'number', {:description => "Height in inches"})
448
+ end
449
+ end
450
+
451
+ end
452
+
453
+
454
+ #=========================================================
455
+ # PetsUsingAutoViewsController is a demonstration of how
456
+ # responses can be described using logic
457
+ #=========================================================
458
+
459
+ describe PetsUsingAutoViewsController do
460
+
461
+ describe "PetsController#pet_described_using_automated_view" do
462
+ subject do
463
+ desc._methods[:pet_described_using_automated_view]
464
+ end
465
+
466
+ it "should return code 200 with array of entries of the format {'pet_name', 'animal_type'}" do
467
+ returns_obj = subject.returns.detect{|e| e.code == 200 }
468
+
469
+ expect(returns_obj.code).to eq(200)
470
+ expect(returns_obj.is_array?).to eq(false)
471
+ expect(returns_obj).to match_field_structure([:pet_name, :animal_type, :age])
472
+ end
473
+
474
+ it 'should have the response described in the swagger' do
475
+ response = swagger_response_for('/pet_described_using_automated_view/{id}')
476
+ expect(response[:description]).to eq("like Pet, but different")
477
+
478
+ schema = response[:schema]
479
+ expect(schema[:type]).to eq("object")
480
+
481
+ expect(schema).to have_field(:pet_name, 'string', {:required => true})
482
+ expect(schema).to have_field(:animal_type, 'string', {:required => true})
483
+ expect(schema).to have_field(:age, 'number', {:required => true})
484
+ end
485
+ end
486
+ end
487
+
488
+
489
+ end