grape 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -66
- data/.rubocop_todo.yml +78 -17
- data/.travis.yml +7 -3
- data/Appraisals +7 -0
- data/CHANGELOG.md +24 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +1 -7
- data/Guardfile +1 -1
- data/README.md +560 -94
- data/RELEASING.md +1 -1
- data/Rakefile +10 -11
- data/UPGRADING.md +211 -3
- data/gemfiles/rails_3.gemfile +14 -0
- data/gemfiles/rails_4.gemfile +14 -0
- data/grape.gemspec +10 -9
- data/lib/backports/active_support/deep_dup.rb +49 -0
- data/lib/backports/active_support/duplicable.rb +88 -0
- data/lib/grape.rb +29 -2
- data/lib/grape/api.rb +59 -65
- data/lib/grape/dsl/api.rb +19 -0
- data/lib/grape/dsl/callbacks.rb +6 -4
- data/lib/grape/dsl/configuration.rb +49 -5
- data/lib/grape/dsl/helpers.rb +7 -8
- data/lib/grape/dsl/inside_route.rb +22 -10
- data/lib/grape/dsl/middleware.rb +5 -5
- data/lib/grape/dsl/parameters.rb +6 -2
- data/lib/grape/dsl/request_response.rb +23 -20
- data/lib/grape/dsl/routing.rb +52 -49
- data/lib/grape/dsl/settings.rb +110 -0
- data/lib/grape/dsl/validations.rb +14 -6
- data/lib/grape/endpoint.rb +104 -88
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/missing_option.rb +1 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
- data/lib/grape/exceptions/unknown_options.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/xml.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/dsl.rb +26 -21
- data/lib/grape/middleware/auth/strategies.rb +1 -1
- data/lib/grape/middleware/auth/strategy_info.rb +0 -2
- data/lib/grape/middleware/base.rb +2 -2
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/middleware/versioner.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +3 -3
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/path.rb +9 -3
- data/lib/grape/util/content_types.rb +16 -8
- data/lib/grape/util/inheritable_setting.rb +74 -0
- data/lib/grape/util/inheritable_values.rb +51 -0
- data/lib/grape/util/stackable_values.rb +52 -0
- data/lib/grape/util/strict_hash_configuration.rb +106 -0
- data/lib/grape/validations.rb +0 -220
- data/lib/grape/validations/attributes_iterator.rb +21 -0
- data/lib/grape/validations/params_scope.rb +176 -0
- data/lib/grape/validations/validators/all_or_none.rb +20 -0
- data/lib/grape/validations/validators/allow_blank.rb +30 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +20 -0
- data/lib/grape/validations/validators/base.rb +37 -0
- data/lib/grape/validations/{coerce.rb → validators/coerce.rb} +3 -3
- data/lib/grape/validations/{default.rb → validators/default.rb} +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +20 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +26 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +25 -0
- data/lib/grape/validations/{presence.rb → validators/presence.rb} +2 -2
- data/lib/grape/validations/validators/regexp.rb +12 -0
- data/lib/grape/validations/validators/values.rb +26 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +522 -343
- data/spec/grape/dsl/callbacks_spec.rb +4 -4
- data/spec/grape/dsl/configuration_spec.rb +48 -9
- data/spec/grape/dsl/helpers_spec.rb +6 -13
- data/spec/grape/dsl/inside_route_spec.rb +43 -4
- data/spec/grape/dsl/middleware_spec.rb +1 -10
- data/spec/grape/dsl/parameters_spec.rb +8 -1
- data/spec/grape/dsl/request_response_spec.rb +16 -22
- data/spec/grape/dsl/routing_spec.rb +21 -5
- data/spec/grape/dsl/settings_spec.rb +219 -0
- data/spec/grape/dsl/validations_spec.rb +8 -11
- data/spec/grape/endpoint_spec.rb +115 -86
- data/spec/grape/entity_spec.rb +33 -33
- data/spec/grape/exceptions/invalid_formatter_spec.rb +3 -5
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +4 -6
- data/spec/grape/exceptions/missing_mime_type_spec.rb +5 -6
- data/spec/grape/exceptions/missing_option_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_options_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_validator_spec.rb +3 -5
- data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
- data/spec/grape/loading_spec.rb +44 -0
- data/spec/grape/middleware/auth/base_spec.rb +0 -4
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -4
- data/spec/grape/middleware/auth/strategies_spec.rb +5 -6
- data/spec/grape/middleware/exception_spec.rb +8 -10
- data/spec/grape/middleware/formatter_spec.rb +13 -15
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +10 -10
- data/spec/grape/middleware/versioner/header_spec.rb +25 -25
- data/spec/grape/middleware/versioner/param_spec.rb +15 -17
- data/spec/grape/middleware/versioner/path_spec.rb +1 -2
- data/spec/grape/middleware/versioner_spec.rb +0 -1
- data/spec/grape/path_spec.rb +66 -45
- data/spec/grape/util/inheritable_setting_spec.rb +217 -0
- data/spec/grape/util/inheritable_values_spec.rb +63 -0
- data/spec/grape/util/stackable_values_spec.rb +115 -0
- data/spec/grape/util/strict_hash_configuration_spec.rb +38 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +4 -0
- data/spec/grape/validations/params_scope_spec.rb +57 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +60 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +170 -0
- data/spec/grape/validations/{at_least_one_of_spec.rb → validators/at_least_one_of_spec.rb} +7 -3
- data/spec/grape/validations/{coerce_spec.rb → validators/coerce_spec.rb} +8 -11
- data/spec/grape/validations/{default_spec.rb → validators/default_spec.rb} +7 -9
- data/spec/grape/validations/{exactly_one_of_spec.rb → validators/exactly_one_of_spec.rb} +15 -11
- data/spec/grape/validations/{mutual_exclusion_spec.rb → validators/mutual_exclusion_spec.rb} +11 -9
- data/spec/grape/validations/{presence_spec.rb → validators/presence_spec.rb} +30 -30
- data/spec/grape/validations/{regexp_spec.rb → validators/regexp_spec.rb} +2 -4
- data/spec/grape/validations/{values_spec.rb → validators/values_spec.rb} +95 -23
- data/spec/grape/validations/{zh-CN.yml → validators/zh-CN.yml} +0 -0
- data/spec/grape/validations_spec.rb +335 -70
- data/spec/shared/versioning_examples.rb +7 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/content_type_helpers.rb +1 -1
- data/spec/support/versioned_helpers.rb +3 -3
- metadata +80 -33
- data/lib/grape/util/deep_merge.rb +0 -23
- data/lib/grape/util/hash_stack.rb +0 -120
- data/lib/grape/validations/at_least_one_of.rb +0 -25
- data/lib/grape/validations/exactly_one_of.rb +0 -26
- data/lib/grape/validations/mutual_exclusion.rb +0 -25
- data/lib/grape/validations/regexp.rb +0 -12
- data/lib/grape/validations/values.rb +0 -23
- data/spec/grape/util/hash_stack_spec.rb +0 -132
@@ -0,0 +1,219 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module SettingsSpec
|
6
|
+
class Dummy
|
7
|
+
include Grape::DSL::Settings
|
8
|
+
|
9
|
+
def reset_validations!; end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Settings do
|
14
|
+
subject { SettingsSpec::Dummy.new }
|
15
|
+
|
16
|
+
describe '#unset' do
|
17
|
+
it 'deletes a key from settings' do
|
18
|
+
subject.namespace_setting :dummy, 1
|
19
|
+
expect(subject.inheritable_setting.namespace.keys).to include(:dummy)
|
20
|
+
|
21
|
+
subject.unset :namespace, :dummy
|
22
|
+
expect(subject.inheritable_setting.namespace.keys).not_to include(:dummy)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#get_or_set' do
|
27
|
+
it 'sets a values' do
|
28
|
+
subject.get_or_set :namespace, :dummy, 1
|
29
|
+
expect(subject.namespace_setting(:dummy)).to eq 1
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns a value when nil is new value is provided' do
|
33
|
+
subject.get_or_set :namespace, :dummy, 1
|
34
|
+
expect(subject.get_or_set(:namespace, :dummy, nil)).to eq 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#global_setting' do
|
39
|
+
it 'delegates to get_or_set' do
|
40
|
+
expect(subject).to receive(:get_or_set).with(:global, :dummy, 1)
|
41
|
+
subject.global_setting(:dummy, 1)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#route_setting' do
|
46
|
+
it 'delegates to get_or_set' do
|
47
|
+
expect(subject).to receive(:get_or_set).with(:route, :dummy, 1)
|
48
|
+
subject.route_setting(:dummy, 1)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'sets a value until the next route' do
|
52
|
+
subject.route_setting :some_thing, :foo_bar
|
53
|
+
expect(subject.route_setting(:some_thing)).to eq :foo_bar
|
54
|
+
|
55
|
+
subject.route_end
|
56
|
+
|
57
|
+
expect(subject.route_setting(:some_thing)).to be_nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#namespace_setting' do
|
62
|
+
it 'delegates to get_or_set' do
|
63
|
+
expect(subject).to receive(:get_or_set).with(:namespace, :dummy, 1)
|
64
|
+
subject.namespace_setting(:dummy, 1)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'sets a value until the end of a namespace' do
|
68
|
+
subject.namespace_start
|
69
|
+
|
70
|
+
subject.namespace_setting :some_thing, :foo_bar
|
71
|
+
expect(subject.namespace_setting(:some_thing)).to eq :foo_bar
|
72
|
+
|
73
|
+
subject.namespace_end
|
74
|
+
|
75
|
+
expect(subject.namespace_setting(:some_thing)).to be_nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'resets values after leaving nested namespaces' do
|
79
|
+
subject.namespace_start
|
80
|
+
|
81
|
+
subject.namespace_setting :some_thing, :foo_bar
|
82
|
+
expect(subject.namespace_setting(:some_thing)).to eq :foo_bar
|
83
|
+
|
84
|
+
subject.namespace_start
|
85
|
+
|
86
|
+
expect(subject.namespace_setting(:some_thing)).to be_nil
|
87
|
+
|
88
|
+
subject.namespace_end
|
89
|
+
expect(subject.namespace_setting(:some_thing)).to eq :foo_bar
|
90
|
+
|
91
|
+
subject.namespace_end
|
92
|
+
|
93
|
+
expect(subject.namespace_setting(:some_thing)).to be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#namespace_inheritable' do
|
98
|
+
it 'delegates to get_or_set' do
|
99
|
+
expect(subject).to receive(:get_or_set).with(:namespace_inheritable, :dummy, 1)
|
100
|
+
subject.namespace_inheritable(:dummy, 1)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'inherits values from surrounding namespace' do
|
104
|
+
subject.namespace_start
|
105
|
+
|
106
|
+
subject.namespace_inheritable(:some_thing, :foo_bar)
|
107
|
+
expect(subject.namespace_inheritable(:some_thing)).to eq :foo_bar
|
108
|
+
|
109
|
+
subject.namespace_start
|
110
|
+
|
111
|
+
expect(subject.namespace_inheritable(:some_thing)).to eq :foo_bar
|
112
|
+
|
113
|
+
subject.namespace_inheritable(:some_thing, :foo_bar_2)
|
114
|
+
|
115
|
+
expect(subject.namespace_inheritable(:some_thing)).to eq :foo_bar_2
|
116
|
+
|
117
|
+
subject.namespace_end
|
118
|
+
expect(subject.namespace_inheritable(:some_thing)).to eq :foo_bar
|
119
|
+
subject.namespace_end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#namespace_stackable' do
|
124
|
+
it 'delegates to get_or_set' do
|
125
|
+
expect(subject).to receive(:get_or_set).with(:namespace_stackable, :dummy, 1)
|
126
|
+
subject.namespace_stackable(:dummy, 1)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'stacks values from surrounding namespace' do
|
130
|
+
subject.namespace_start
|
131
|
+
|
132
|
+
subject.namespace_stackable(:some_thing, :foo_bar)
|
133
|
+
expect(subject.namespace_stackable(:some_thing)).to eq [:foo_bar]
|
134
|
+
|
135
|
+
subject.namespace_start
|
136
|
+
|
137
|
+
expect(subject.namespace_stackable(:some_thing)).to eq [:foo_bar]
|
138
|
+
|
139
|
+
subject.namespace_stackable(:some_thing, :foo_bar_2)
|
140
|
+
|
141
|
+
expect(subject.namespace_stackable(:some_thing)).to eq [:foo_bar, :foo_bar_2]
|
142
|
+
|
143
|
+
subject.namespace_end
|
144
|
+
expect(subject.namespace_stackable(:some_thing)).to eq [:foo_bar]
|
145
|
+
subject.namespace_end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#api_class_setting' do
|
150
|
+
it 'delegates to get_or_set' do
|
151
|
+
expect(subject).to receive(:get_or_set).with(:api_class, :dummy, 1)
|
152
|
+
subject.api_class_setting(:dummy, 1)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#within_namespace' do
|
157
|
+
it 'calls start and end for a namespace' do
|
158
|
+
expect(subject).to receive :namespace_start
|
159
|
+
expect(subject).to receive :namespace_end
|
160
|
+
|
161
|
+
subject.within_namespace do
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'returns the last result' do
|
166
|
+
result = subject.within_namespace do
|
167
|
+
1
|
168
|
+
end
|
169
|
+
|
170
|
+
expect(result).to eq 1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'complex scenario' do
|
175
|
+
it 'plays well' do
|
176
|
+
obj1 = SettingsSpec::Dummy.new
|
177
|
+
obj2 = SettingsSpec::Dummy.new
|
178
|
+
obj3 = SettingsSpec::Dummy.new
|
179
|
+
|
180
|
+
obj1_copy = nil
|
181
|
+
obj2_copy = nil
|
182
|
+
obj3_copy = nil
|
183
|
+
|
184
|
+
obj1.within_namespace do
|
185
|
+
obj1.namespace_stackable(:some_thing, :obj1)
|
186
|
+
expect(obj1.namespace_stackable(:some_thing)).to eq [:obj1]
|
187
|
+
obj1_copy = obj1.inheritable_setting.point_in_time_copy
|
188
|
+
end
|
189
|
+
|
190
|
+
expect(obj1.namespace_stackable(:some_thing)).to eq []
|
191
|
+
expect(obj1_copy.namespace_stackable[:some_thing]).to eq [:obj1]
|
192
|
+
|
193
|
+
obj2.within_namespace do
|
194
|
+
obj2.namespace_stackable(:some_thing, :obj2)
|
195
|
+
expect(obj2.namespace_stackable(:some_thing)).to eq [:obj2]
|
196
|
+
obj2_copy = obj2.inheritable_setting.point_in_time_copy
|
197
|
+
end
|
198
|
+
|
199
|
+
expect(obj2.namespace_stackable(:some_thing)).to eq []
|
200
|
+
expect(obj2_copy.namespace_stackable[:some_thing]).to eq [:obj2]
|
201
|
+
|
202
|
+
obj3.within_namespace do
|
203
|
+
obj3.namespace_stackable(:some_thing, :obj3)
|
204
|
+
expect(obj3.namespace_stackable(:some_thing)).to eq [:obj3]
|
205
|
+
obj3_copy = obj3.inheritable_setting.point_in_time_copy
|
206
|
+
end
|
207
|
+
|
208
|
+
expect(obj3.namespace_stackable(:some_thing)).to eq []
|
209
|
+
expect(obj3_copy.namespace_stackable[:some_thing]).to eq [:obj3]
|
210
|
+
|
211
|
+
obj1.top_level_setting.inherit_from obj2_copy.point_in_time_copy
|
212
|
+
obj2.top_level_setting.inherit_from obj3_copy.point_in_time_copy
|
213
|
+
|
214
|
+
expect(obj1_copy.namespace_stackable[:some_thing]).to eq [:obj3, :obj2, :obj1]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -5,10 +5,6 @@ module Grape
|
|
5
5
|
module ValidationsSpec
|
6
6
|
class Dummy
|
7
7
|
include Grape::DSL::Validations
|
8
|
-
|
9
|
-
def self.settings
|
10
|
-
@settings ||= Grape::Util::HashStack.new
|
11
|
-
end
|
12
8
|
end
|
13
9
|
end
|
14
10
|
|
@@ -17,17 +13,17 @@ module Grape
|
|
17
13
|
|
18
14
|
describe '.reset_validations!' do
|
19
15
|
before do
|
20
|
-
subject.
|
21
|
-
subject.
|
16
|
+
subject.namespace_stackable :declared_params, ['dummy']
|
17
|
+
subject.namespace_stackable :validations, ['dummy']
|
22
18
|
subject.reset_validations!
|
23
19
|
end
|
24
20
|
|
25
21
|
it 'resets declared params' do
|
26
|
-
expect(subject.
|
22
|
+
expect(subject.namespace_stackable(:declared_params)).to eq []
|
27
23
|
end
|
28
24
|
|
29
25
|
it 'resets validations' do
|
30
|
-
expect(subject.
|
26
|
+
expect(subject.namespace_stackable(:validations)).to eq []
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
@@ -37,7 +33,7 @@ module Grape
|
|
37
33
|
end
|
38
34
|
|
39
35
|
it 'evaluates block' do
|
40
|
-
expect { subject.params {
|
36
|
+
expect { subject.params { fail 'foo' } }.to raise_error RuntimeError, 'foo'
|
41
37
|
end
|
42
38
|
end
|
43
39
|
|
@@ -46,8 +42,9 @@ module Grape
|
|
46
42
|
subject.document_attribute([full_name: 'xxx'], foo: 'bar')
|
47
43
|
end
|
48
44
|
|
49
|
-
it 'creates
|
50
|
-
expect(subject.
|
45
|
+
it 'creates a param documentation' do
|
46
|
+
expect(subject.namespace_stackable(:params)).to eq(['xxx' => { foo: 'bar' }])
|
47
|
+
expect(subject.route_setting(:description)).to eq(params: { 'xxx' => { foo: 'bar' } })
|
51
48
|
end
|
52
49
|
end
|
53
50
|
end
|
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -11,27 +11,27 @@ describe Grape::Endpoint do
|
|
11
11
|
after { Grape::Endpoint.before_each(nil) }
|
12
12
|
|
13
13
|
it 'should be settable via block' do
|
14
|
-
block = lambda { |endpoint|
|
14
|
+
block = lambda { |endpoint| 'noop' }
|
15
15
|
Grape::Endpoint.before_each(&block)
|
16
16
|
expect(Grape::Endpoint.before_each).to eq(block)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should be settable via reference' do
|
20
|
-
block = lambda { |endpoint|
|
20
|
+
block = lambda { |endpoint| 'noop' }
|
21
21
|
Grape::Endpoint.before_each block
|
22
22
|
expect(Grape::Endpoint.before_each).to eq(block)
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'should be able to override a helper' do
|
26
|
-
subject.get(
|
26
|
+
subject.get('/') { current_user }
|
27
27
|
expect { get '/' }.to raise_error(NameError)
|
28
28
|
|
29
29
|
Grape::Endpoint.before_each do |endpoint|
|
30
|
-
allow(endpoint).to receive(:current_user).and_return(
|
30
|
+
allow(endpoint).to receive(:current_user).and_return('Bob')
|
31
31
|
end
|
32
32
|
|
33
33
|
get '/'
|
34
|
-
expect(last_response.body).to eq(
|
34
|
+
expect(last_response.body).to eq('Bob')
|
35
35
|
|
36
36
|
Grape::Endpoint.before_each(nil)
|
37
37
|
expect { get '/' }.to raise_error(NameError)
|
@@ -41,17 +41,17 @@ describe Grape::Endpoint do
|
|
41
41
|
describe '#initialize' do
|
42
42
|
it 'takes a settings stack, options, and a block' do
|
43
43
|
p = proc {}
|
44
|
-
expect
|
45
|
-
Grape::Endpoint.new(Grape::Util::
|
44
|
+
expect do
|
45
|
+
Grape::Endpoint.new(Grape::Util::InheritableSetting.new, {
|
46
46
|
path: '/',
|
47
47
|
method: :get
|
48
48
|
}, &p)
|
49
|
-
|
49
|
+
end.not_to raise_error
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'sets itself in the env upon call' do
|
54
|
-
subject.get('/') {
|
54
|
+
subject.get('/') { 'Hello world.' }
|
55
55
|
get '/'
|
56
56
|
expect(last_request.env['api.endpoint']).to be_kind_of(Grape::Endpoint)
|
57
57
|
end
|
@@ -60,47 +60,46 @@ describe Grape::Endpoint do
|
|
60
60
|
it 'is callable from within a block' do
|
61
61
|
subject.get('/home') do
|
62
62
|
status 206
|
63
|
-
|
63
|
+
'Hello'
|
64
64
|
end
|
65
65
|
|
66
66
|
get '/home'
|
67
67
|
expect(last_response.status).to eq(206)
|
68
|
-
expect(last_response.body).to eq(
|
68
|
+
expect(last_response.body).to eq('Hello')
|
69
69
|
end
|
70
70
|
|
71
71
|
it 'is set as default to 200 for get' do
|
72
72
|
memoized_status = nil
|
73
73
|
subject.get('/home') do
|
74
74
|
memoized_status = status
|
75
|
-
|
75
|
+
'Hello'
|
76
76
|
end
|
77
77
|
|
78
78
|
get '/home'
|
79
79
|
expect(last_response.status).to eq(200)
|
80
80
|
expect(memoized_status).to eq(200)
|
81
|
-
expect(last_response.body).to eq(
|
81
|
+
expect(last_response.body).to eq('Hello')
|
82
82
|
end
|
83
83
|
|
84
84
|
it 'is set as default to 201 for post' do
|
85
85
|
memoized_status = nil
|
86
86
|
subject.post('/home') do
|
87
87
|
memoized_status = status
|
88
|
-
|
88
|
+
'Hello'
|
89
89
|
end
|
90
90
|
|
91
91
|
post '/home'
|
92
92
|
expect(last_response.status).to eq(201)
|
93
93
|
expect(memoized_status).to eq(201)
|
94
|
-
expect(last_response.body).to eq(
|
94
|
+
expect(last_response.body).to eq('Hello')
|
95
95
|
end
|
96
|
-
|
97
96
|
end
|
98
97
|
|
99
98
|
describe '#header' do
|
100
99
|
it 'is callable from within a block' do
|
101
100
|
subject.get('/hey') do
|
102
101
|
header 'X-Awesome', 'true'
|
103
|
-
|
102
|
+
'Awesome'
|
104
103
|
end
|
105
104
|
|
106
105
|
get '/hey'
|
@@ -117,19 +116,19 @@ describe Grape::Endpoint do
|
|
117
116
|
it 'includes request headers' do
|
118
117
|
get '/headers'
|
119
118
|
expect(JSON.parse(last_response.body)).to eq(
|
120
|
-
|
121
|
-
|
119
|
+
'Host' => 'example.org',
|
120
|
+
'Cookie' => ''
|
122
121
|
)
|
123
122
|
end
|
124
123
|
it 'includes additional request headers' do
|
125
|
-
get '/headers', nil,
|
126
|
-
expect(JSON.parse(last_response.body)[
|
124
|
+
get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
|
125
|
+
expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
|
127
126
|
end
|
128
127
|
it 'includes headers passed as symbols' do
|
129
|
-
env = Rack::MockRequest.env_for(
|
130
|
-
env[
|
128
|
+
env = Rack::MockRequest.env_for('/headers')
|
129
|
+
env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols'
|
131
130
|
body = subject.call(env)[2].body.first
|
132
|
-
expect(JSON.parse(body)[
|
131
|
+
expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
|
133
132
|
end
|
134
133
|
end
|
135
134
|
|
@@ -150,10 +149,10 @@ describe Grape::Endpoint do
|
|
150
149
|
get('/get/cookies')
|
151
150
|
|
152
151
|
expect(last_response.headers['Set-Cookie'].split("\n").sort).to eql [
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
152
|
+
'cookie3=symbol',
|
153
|
+
'cookie4=secret+code+here',
|
154
|
+
'my-awesome-cookie1=is+cool',
|
155
|
+
'my-awesome-cookie2=is+cool+too; domain=my.example.com; path=/; secure'
|
157
156
|
]
|
158
157
|
end
|
159
158
|
|
@@ -170,7 +169,7 @@ describe Grape::Endpoint do
|
|
170
169
|
it 'sets and update browser cookies' do
|
171
170
|
subject.get('/username') do
|
172
171
|
cookies[:sandbox] = true if cookies[:sandbox] == 'false'
|
173
|
-
cookies[:username] +=
|
172
|
+
cookies[:username] += '_test'
|
174
173
|
end
|
175
174
|
get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
|
176
175
|
expect(last_response.body).to eq('user_test')
|
@@ -194,10 +193,10 @@ describe Grape::Endpoint do
|
|
194
193
|
[cookie.name, cookie]
|
195
194
|
end]
|
196
195
|
expect(cookies.size).to eq(2)
|
197
|
-
|
196
|
+
%w(and_this delete_this_cookie).each do |cookie_name|
|
198
197
|
cookie = cookies[cookie_name]
|
199
198
|
expect(cookie).not_to be_nil
|
200
|
-
expect(cookie.value).to eq(
|
199
|
+
expect(cookie.value).to eq('deleted')
|
201
200
|
expect(cookie.expired?).to be true
|
202
201
|
end
|
203
202
|
end
|
@@ -218,11 +217,11 @@ describe Grape::Endpoint do
|
|
218
217
|
[cookie.name, cookie]
|
219
218
|
end]
|
220
219
|
expect(cookies.size).to eq(2)
|
221
|
-
|
220
|
+
%w(and_this delete_this_cookie).each do |cookie_name|
|
222
221
|
cookie = cookies[cookie_name]
|
223
222
|
expect(cookie).not_to be_nil
|
224
|
-
expect(cookie.value).to eq(
|
225
|
-
expect(cookie.path).to eq(
|
223
|
+
expect(cookie.value).to eq('deleted')
|
224
|
+
expect(cookie.path).to eq('/test')
|
226
225
|
expect(cookie.expired?).to be true
|
227
226
|
end
|
228
227
|
end
|
@@ -244,7 +243,7 @@ describe Grape::Endpoint do
|
|
244
243
|
inner_params = nil
|
245
244
|
subject.get '/declared' do
|
246
245
|
inner_params = declared(params).keys
|
247
|
-
|
246
|
+
''
|
248
247
|
end
|
249
248
|
get '/declared?first=present'
|
250
249
|
expect(last_response.status).to eq(200)
|
@@ -255,7 +254,7 @@ describe Grape::Endpoint do
|
|
255
254
|
inner_params = nil
|
256
255
|
subject.get '/declared' do
|
257
256
|
inner_params = declared(params)
|
258
|
-
|
257
|
+
''
|
259
258
|
end
|
260
259
|
get '/declared?first=one'
|
261
260
|
expect(last_response.status).to eq(200)
|
@@ -266,7 +265,7 @@ describe Grape::Endpoint do
|
|
266
265
|
inner_params = nil
|
267
266
|
subject.get '/declared' do
|
268
267
|
inner_params = declared(params)
|
269
|
-
|
268
|
+
''
|
270
269
|
end
|
271
270
|
|
272
271
|
get '/declared?first=present&nested[fourth]=1'
|
@@ -288,7 +287,7 @@ describe Grape::Endpoint do
|
|
288
287
|
inner_params = nil
|
289
288
|
subject.get '/declared' do
|
290
289
|
inner_params = declared(params)
|
291
|
-
|
290
|
+
''
|
292
291
|
end
|
293
292
|
|
294
293
|
get '/declared?first=present&nested[][fourth]=1&nested[][fourth]=2'
|
@@ -300,7 +299,7 @@ describe Grape::Endpoint do
|
|
300
299
|
inner_params = nil
|
301
300
|
subject.get '/declared' do
|
302
301
|
inner_params = declared(params)
|
303
|
-
|
302
|
+
''
|
304
303
|
end
|
305
304
|
get '/declared?first=one&other=two'
|
306
305
|
expect(last_response.status).to eq(200)
|
@@ -311,23 +310,57 @@ describe Grape::Endpoint do
|
|
311
310
|
inner_params = nil
|
312
311
|
subject.get '/declared' do
|
313
312
|
inner_params = declared(params, stringify: true)
|
314
|
-
|
313
|
+
''
|
315
314
|
end
|
316
315
|
|
317
316
|
get '/declared?first=one&other=two'
|
318
317
|
expect(last_response.status).to eq(200)
|
319
|
-
expect(inner_params[
|
318
|
+
expect(inner_params['first']).to eq 'one'
|
320
319
|
end
|
321
320
|
|
322
321
|
it 'does not include missing attributes if that option is passed' do
|
323
322
|
subject.get '/declared' do
|
324
|
-
error! 400,
|
325
|
-
|
323
|
+
error! 400, 'expected nil' if declared(params, include_missing: false)[:second]
|
324
|
+
''
|
326
325
|
end
|
327
326
|
|
328
327
|
get '/declared?first=one&other=two'
|
329
328
|
expect(last_response.status).to eq(200)
|
330
329
|
end
|
330
|
+
|
331
|
+
it 'does not include missing attributes when there are nested hashes' do
|
332
|
+
subject.get '/dummy' do
|
333
|
+
end
|
334
|
+
|
335
|
+
subject.params do
|
336
|
+
requires :first
|
337
|
+
optional :second
|
338
|
+
optional :third, default: nil
|
339
|
+
optional :nested, type: Hash do
|
340
|
+
optional :fourth, default: nil
|
341
|
+
optional :fifth, default: nil
|
342
|
+
requires :nested_nested, type: Hash do
|
343
|
+
optional :sixth, default: 'sixth-default'
|
344
|
+
optional :seven, default: nil
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
inner_params = nil
|
350
|
+
subject.get '/declared' do
|
351
|
+
inner_params = declared(params, include_missing: false)
|
352
|
+
''
|
353
|
+
end
|
354
|
+
|
355
|
+
get '/declared?first=present&nested[fourth]=&nested[nested_nested][sixth]=sixth'
|
356
|
+
|
357
|
+
expect(last_response.status).to eq(200)
|
358
|
+
expect(inner_params[:first]).to eq 'present'
|
359
|
+
expect(inner_params[:nested].keys).to eq [:fourth, :nested_nested]
|
360
|
+
expect(inner_params[:nested][:fourth]).to eq ''
|
361
|
+
expect(inner_params[:nested][:nested_nested].keys).to eq [:sixth]
|
362
|
+
expect(inner_params[:nested][:nested_nested][:sixth]).to eq 'sixth'
|
363
|
+
end
|
331
364
|
end
|
332
365
|
|
333
366
|
describe '#declared; call from child namespace' do
|
@@ -451,7 +484,7 @@ describe Grape::Endpoint do
|
|
451
484
|
end
|
452
485
|
end
|
453
486
|
end
|
454
|
-
it
|
487
|
+
it 'parse email param with provided requirements for params' do
|
455
488
|
get '/outer/abc@example.com'
|
456
489
|
expect(last_response.body).to eq('abc@example.com')
|
457
490
|
end
|
@@ -464,7 +497,6 @@ describe Grape::Endpoint do
|
|
464
497
|
expect(last_response.status).to eq(200)
|
465
498
|
expect(last_response.body).to eq('someone@testing.com1')
|
466
499
|
end
|
467
|
-
|
468
500
|
end
|
469
501
|
end
|
470
502
|
|
@@ -500,16 +532,16 @@ describe Grape::Endpoint do
|
|
500
532
|
|
501
533
|
it 'does not include parameters not defined by the body' do
|
502
534
|
subject.post '/omitted_params' do
|
503
|
-
error! 400,
|
535
|
+
error! 400, 'expected nil' if params[:version]
|
504
536
|
params[:user]
|
505
537
|
end
|
506
538
|
post '/omitted_params', MultiJson.dump(user: 'Bob'), 'CONTENT_TYPE' => 'application/json'
|
507
539
|
expect(last_response.status).to eq(201)
|
508
|
-
expect(last_response.body).to eq(
|
540
|
+
expect(last_response.body).to eq('Bob')
|
509
541
|
end
|
510
542
|
end
|
511
543
|
|
512
|
-
it
|
544
|
+
it 'responds with a 406 for an unsupported content-type' do
|
513
545
|
subject.format :json
|
514
546
|
# subject.content_type :json, "application/json"
|
515
547
|
subject.put '/request_body' do
|
@@ -531,18 +563,16 @@ describe Grape::Endpoint do
|
|
531
563
|
post '/', MultiJson.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
|
532
564
|
end
|
533
565
|
|
534
|
-
it
|
566
|
+
it 'should not response with 406 for same type without params' do
|
535
567
|
expect(last_response.status).not_to be 406
|
536
568
|
end
|
537
569
|
|
538
|
-
it
|
570
|
+
it 'should response with given content type in headers' do
|
539
571
|
expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
|
540
572
|
end
|
541
|
-
|
542
573
|
end
|
543
574
|
|
544
575
|
context 'precedence' do
|
545
|
-
|
546
576
|
before do
|
547
577
|
subject.format :json
|
548
578
|
subject.namespace '/:id' do
|
@@ -578,29 +608,28 @@ describe Grape::Endpoint do
|
|
578
608
|
expect(JSON.parse(last_response.body)['params']).to eq '123'
|
579
609
|
end
|
580
610
|
end
|
581
|
-
|
582
611
|
end
|
583
612
|
|
584
613
|
describe '#error!' do
|
585
614
|
it 'accepts a message' do
|
586
615
|
subject.get('/hey') do
|
587
|
-
error!
|
588
|
-
|
616
|
+
error! 'This is not valid.'
|
617
|
+
'This is valid.'
|
589
618
|
end
|
590
619
|
|
591
620
|
get '/hey'
|
592
621
|
expect(last_response.status).to eq(500)
|
593
|
-
expect(last_response.body).to eq(
|
622
|
+
expect(last_response.body).to eq('This is not valid.')
|
594
623
|
end
|
595
624
|
|
596
625
|
it 'accepts a code' do
|
597
626
|
subject.get('/hey') do
|
598
|
-
error!
|
627
|
+
error! 'Unauthorized.', 401
|
599
628
|
end
|
600
629
|
|
601
630
|
get '/hey'
|
602
631
|
expect(last_response.status).to eq(401)
|
603
|
-
expect(last_response.body).to eq(
|
632
|
+
expect(last_response.body).to eq('Unauthorized.')
|
604
633
|
end
|
605
634
|
|
606
635
|
it 'accepts an object and render it in format' do
|
@@ -640,31 +669,31 @@ describe Grape::Endpoint do
|
|
640
669
|
describe '#redirect' do
|
641
670
|
it 'redirects to a url with status 302' do
|
642
671
|
subject.get('/hey') do
|
643
|
-
redirect
|
672
|
+
redirect '/ha'
|
644
673
|
end
|
645
674
|
get '/hey'
|
646
675
|
expect(last_response.status).to eq 302
|
647
|
-
expect(last_response.headers['Location']).to eq
|
648
|
-
expect(last_response.body).to eq
|
676
|
+
expect(last_response.headers['Location']).to eq '/ha'
|
677
|
+
expect(last_response.body).to eq ''
|
649
678
|
end
|
650
679
|
|
651
680
|
it 'has status code 303 if it is not get request and it is http 1.1' do
|
652
681
|
subject.post('/hey') do
|
653
|
-
redirect
|
682
|
+
redirect '/ha'
|
654
683
|
end
|
655
684
|
post '/hey', {}, 'HTTP_VERSION' => 'HTTP/1.1'
|
656
685
|
expect(last_response.status).to eq 303
|
657
|
-
expect(last_response.headers['Location']).to eq
|
686
|
+
expect(last_response.headers['Location']).to eq '/ha'
|
658
687
|
end
|
659
688
|
|
660
689
|
it 'support permanent redirect' do
|
661
690
|
subject.get('/hey') do
|
662
|
-
redirect
|
691
|
+
redirect '/ha', permanent: true
|
663
692
|
end
|
664
693
|
get '/hey'
|
665
694
|
expect(last_response.status).to eq 301
|
666
|
-
expect(last_response.headers['Location']).to eq
|
667
|
-
expect(last_response.body).to eq
|
695
|
+
expect(last_response.headers['Location']).to eq '/ha'
|
696
|
+
expect(last_response.body).to eq ''
|
668
697
|
end
|
669
698
|
end
|
670
699
|
|
@@ -699,54 +728,54 @@ describe Grape::Endpoint do
|
|
699
728
|
|
700
729
|
it 'allows explicit return calls' do
|
701
730
|
subject.get('/home') do
|
702
|
-
return
|
731
|
+
return 'Hello'
|
703
732
|
end
|
704
733
|
|
705
734
|
get '/home'
|
706
735
|
expect(last_response.status).to eq(200)
|
707
|
-
expect(last_response.body).to eq(
|
736
|
+
expect(last_response.body).to eq('Hello')
|
708
737
|
end
|
709
738
|
|
710
739
|
describe '.generate_api_method' do
|
711
740
|
it 'raises NameError if the method name is already in use' do
|
712
|
-
expect
|
713
|
-
Grape::Endpoint.generate_api_method(
|
714
|
-
|
741
|
+
expect do
|
742
|
+
Grape::Endpoint.generate_api_method('version', &proc {})
|
743
|
+
end.to raise_error(NameError)
|
715
744
|
end
|
716
745
|
it 'raises ArgumentError if a block is not given' do
|
717
|
-
expect
|
718
|
-
Grape::Endpoint.generate_api_method(
|
719
|
-
|
746
|
+
expect do
|
747
|
+
Grape::Endpoint.generate_api_method('GET without a block method')
|
748
|
+
end.to raise_error(ArgumentError)
|
720
749
|
end
|
721
750
|
it 'returns a Proc' do
|
722
|
-
expect(Grape::Endpoint.generate_api_method(
|
751
|
+
expect(Grape::Endpoint.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
|
723
752
|
end
|
724
753
|
end
|
725
754
|
|
726
755
|
context 'filters' do
|
727
756
|
describe 'before filters' do
|
728
757
|
it 'runs the before filter if set' do
|
729
|
-
subject.before { env['before_test'] =
|
758
|
+
subject.before { env['before_test'] = 'OK' }
|
730
759
|
subject.get('/before_test') { env['before_test'] }
|
731
760
|
|
732
761
|
get '/before_test'
|
733
|
-
expect(last_response.body).to eq(
|
762
|
+
expect(last_response.body).to eq('OK')
|
734
763
|
end
|
735
764
|
end
|
736
765
|
|
737
766
|
describe 'after filters' do
|
738
767
|
it 'overrides the response body if it sets it' do
|
739
|
-
subject.after { body
|
740
|
-
subject.get('/after_test') {
|
768
|
+
subject.after { body 'after' }
|
769
|
+
subject.get('/after_test') { 'during' }
|
741
770
|
get '/after_test'
|
742
771
|
expect(last_response.body).to eq('after')
|
743
772
|
end
|
744
773
|
|
745
774
|
it 'does not override the response body with its return' do
|
746
|
-
subject.after {
|
747
|
-
subject.get('/after_test') {
|
775
|
+
subject.after { 'after' }
|
776
|
+
subject.get('/after_test') { 'body' }
|
748
777
|
get '/after_test'
|
749
|
-
expect(last_response.body).to eq(
|
778
|
+
expect(last_response.body).to eq('body')
|
750
779
|
end
|
751
780
|
end
|
752
781
|
end
|
@@ -776,7 +805,7 @@ describe Grape::Endpoint do
|
|
776
805
|
verb
|
777
806
|
end
|
778
807
|
send(verb, '/example/and/some/more')
|
779
|
-
expect(last_response.status).to eql verb ==
|
808
|
+
expect(last_response.status).to eql verb == 'post' ? 201 : 200
|
780
809
|
expect(last_response.body).to eql verb == 'head' ? '' : verb
|
781
810
|
end
|
782
811
|
end
|
@@ -788,7 +817,7 @@ describe Grape::Endpoint do
|
|
788
817
|
request.url
|
789
818
|
end
|
790
819
|
get '/url'
|
791
|
-
expect(last_response.body).to eq(
|
820
|
+
expect(last_response.body).to eq('http://example.org/url')
|
792
821
|
end
|
793
822
|
['v1', :v1].each do |version|
|
794
823
|
it 'should include version #{version}' do
|
@@ -807,7 +836,7 @@ describe Grape::Endpoint do
|
|
807
836
|
request.url
|
808
837
|
end
|
809
838
|
get '/api/v1/url'
|
810
|
-
expect(last_response.body).to eq(
|
839
|
+
expect(last_response.body).to eq('http://example.org/api/v1/url')
|
811
840
|
end
|
812
841
|
end
|
813
842
|
|
@@ -816,7 +845,7 @@ describe Grape::Endpoint do
|
|
816
845
|
# NOTE: a 404 is returned instead of the 406 if cascade: false is not set.
|
817
846
|
subject.version 'v1', using: :header, vendor: 'ohanapi', cascade: false
|
818
847
|
subject.get '/test' do
|
819
|
-
|
848
|
+
'Hello!'
|
820
849
|
end
|
821
850
|
end
|
822
851
|
|