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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
- data/README.rst +320 -2
- data/lib/apipie-rails.rb +2 -0
- data/lib/apipie/application.rb +1 -1
- data/lib/apipie/configuration.rb +5 -2
- data/lib/apipie/dsl_definition.rb +69 -1
- data/lib/apipie/errors.rb +6 -1
- data/lib/apipie/extractor/writer.rb +65 -42
- data/lib/apipie/method_description.rb +32 -2
- data/lib/apipie/param_description.rb +19 -1
- data/lib/apipie/resource_description.rb +3 -1
- data/lib/apipie/response_description.rb +125 -0
- data/lib/apipie/response_description_adapter.rb +199 -0
- data/lib/apipie/swagger_generator.rb +106 -16
- data/lib/apipie/version.rb +1 -1
- data/spec/controllers/apipies_controller_spec.rb +1 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/pets_controller.rb +391 -0
- data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
- data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
- data/spec/lib/extractor/writer_spec.rb +32 -4
- data/spec/lib/method_description_spec.rb +27 -0
- data/spec/lib/swagger/rake_swagger_spec.rb +4 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +489 -0
- data/spec/spec_helper.rb +94 -0
- metadata +13 -2
@@ -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
|
-
|
61
|
-
|
62
|
-
Apipie.configuration.doc_path
|
63
|
-
|
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
|