grape 1.6.0 → 1.6.2
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 +26 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +9 -1
- data/UPGRADING.md +4 -4
- data/lib/grape/api.rb +12 -0
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +1 -1
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +1 -1
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/validators/all_or_none.rb +7 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +7 -5
- data/lib/grape/validations/validators/at_least_one_of.rb +6 -4
- data/lib/grape/validations/validators/base.rb +73 -71
- data/lib/grape/validations/validators/coerce.rb +63 -75
- data/lib/grape/validations/validators/default.rb +36 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +8 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -22
- data/lib/grape/validations/validators/mutual_exclusion.rb +7 -5
- data/lib/grape/validations/validators/presence.rb +6 -4
- data/lib/grape/validations/validators/regexp.rb +7 -5
- data/lib/grape/validations/validators/same_as.rb +17 -15
- data/lib/grape/validations/validators/values.rb +59 -57
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +2 -0
- data/spec/grape/api/custom_validations_spec.rb +77 -46
- data/spec/grape/api/deeply_included_options_spec.rb +3 -3
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +1 -1
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +16 -15
- data/spec/grape/api_spec.rb +317 -193
- data/spec/grape/dsl/callbacks_spec.rb +1 -0
- data/spec/grape/dsl/headers_spec.rb +39 -9
- data/spec/grape/dsl/helpers_spec.rb +3 -2
- data/spec/grape/dsl/inside_route_spec.rb +6 -4
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +1 -0
- data/spec/grape/dsl/parameters_spec.rb +1 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +9 -6
- data/spec/grape/endpoint/declared_spec.rb +12 -12
- data/spec/grape/endpoint_spec.rb +59 -50
- data/spec/grape/entity_spec.rb +13 -13
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
- data/spec/grape/exceptions/validation_spec.rb +5 -3
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
- data/spec/grape/integration/rack_sendfile_spec.rb +1 -1
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +14 -5
- data/spec/grape/middleware/auth/strategies_spec.rb +60 -20
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +1 -0
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +25 -4
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +11 -11
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
- data/spec/grape/middleware/versioner/header_spec.rb +14 -13
- data/spec/grape/middleware/versioner/param_spec.rb +7 -1
- data/spec/grape/middleware/versioner/path_spec.rb +5 -1
- data/spec/grape/middleware/versioner_spec.rb +1 -1
- data/spec/grape/parser_spec.rb +4 -0
- data/spec/grape/path_spec.rb +52 -52
- data/spec/grape/presenters/presenter_spec.rb +7 -6
- data/spec/grape/request_spec.rb +6 -4
- data/spec/grape/util/inheritable_setting_spec.rb +7 -7
- data/spec/grape/util/inheritable_values_spec.rb +3 -2
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
- data/spec/grape/util/stackable_values_spec.rb +7 -5
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -0
- data/spec/grape/validations/params_scope_spec.rb +9 -7
- data/spec/grape/validations/single_attribute_iterator_spec.rb +1 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +2 -2
- data/spec/grape/validations/types_spec.rb +8 -8
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
- data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
- data/spec/grape/validations/validators/coerce_spec.rb +10 -12
- data/spec/grape/validations/validators/default_spec.rb +72 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +1 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
- data/spec/grape/validations/validators/presence_spec.rb +16 -1
- data/spec/grape/validations/validators/regexp_spec.rb +25 -31
- data/spec/grape/validations/validators/same_as_spec.rb +14 -20
- data/spec/grape/validations/validators/values_spec.rb +172 -171
- data/spec/grape/validations_spec.rb +45 -16
- data/spec/integration/eager_load/eager_load_spec.rb +2 -2
- data/spec/integration/multi_json/json_spec.rb +1 -1
- data/spec/integration/multi_xml/xml_spec.rb +1 -1
- data/spec/shared/versioning_examples.rb +10 -7
- data/spec/spec_helper.rb +11 -1
- metadata +102 -102
@@ -3,7 +3,8 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Formatter do
|
6
|
-
subject {
|
6
|
+
subject { described_class.new(app) }
|
7
|
+
|
7
8
|
before { allow(subject).to receive(:dup).and_return(subject) }
|
8
9
|
|
9
10
|
let(:body) { { 'foo' => 'bar' } }
|
@@ -11,6 +12,7 @@ describe Grape::Middleware::Formatter do
|
|
11
12
|
|
12
13
|
context 'serialization' do
|
13
14
|
let(:body) { { 'abc' => 'def' } }
|
15
|
+
|
14
16
|
it 'looks at the bodies for possibly serializable data' do
|
15
17
|
_, _, bodies = *subject.call('PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json')
|
16
18
|
bodies.each { |b| expect(b).to eq(::Grape::Json.dump(body)) }
|
@@ -18,6 +20,7 @@ describe Grape::Middleware::Formatter do
|
|
18
20
|
|
19
21
|
context 'default format' do
|
20
22
|
let(:body) { ['foo'] }
|
23
|
+
|
21
24
|
it 'calls #to_json since default format is json' do
|
22
25
|
body.instance_eval do
|
23
26
|
def to_json(*_args)
|
@@ -31,6 +34,7 @@ describe Grape::Middleware::Formatter do
|
|
31
34
|
|
32
35
|
context 'jsonapi' do
|
33
36
|
let(:body) { { 'foos' => [{ 'bar' => 'baz' }] } }
|
37
|
+
|
34
38
|
it 'calls #to_json if the content type is jsonapi' do
|
35
39
|
body.instance_eval do
|
36
40
|
def to_json(*_args)
|
@@ -44,6 +48,7 @@ describe Grape::Middleware::Formatter do
|
|
44
48
|
|
45
49
|
context 'xml' do
|
46
50
|
let(:body) { +'string' }
|
51
|
+
|
47
52
|
it 'calls #to_xml if the content type is xml' do
|
48
53
|
body.instance_eval do
|
49
54
|
def to_xml
|
@@ -58,6 +63,7 @@ describe Grape::Middleware::Formatter do
|
|
58
63
|
|
59
64
|
context 'error handling' do
|
60
65
|
let(:formatter) { double(:formatter) }
|
66
|
+
|
61
67
|
before do
|
62
68
|
allow(Grape::Formatter).to receive(:formatter_for) { formatter }
|
63
69
|
end
|
@@ -67,7 +73,7 @@ describe Grape::Middleware::Formatter do
|
|
67
73
|
|
68
74
|
expect do
|
69
75
|
catch(:error) { subject.call('PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
|
70
|
-
end.
|
76
|
+
end.not_to raise_error
|
71
77
|
end
|
72
78
|
|
73
79
|
it 'does not rescue other exceptions' do
|
@@ -147,7 +153,7 @@ describe Grape::Middleware::Formatter do
|
|
147
153
|
subject.options[:content_types][:custom] = 'application/vnd.test+json'
|
148
154
|
end
|
149
155
|
|
150
|
-
it '
|
156
|
+
it 'uses the custom type' do
|
151
157
|
subject.call('PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')
|
152
158
|
expect(subject.env['api.format']).to eq(:custom)
|
153
159
|
end
|
@@ -164,26 +170,31 @@ describe Grape::Middleware::Formatter do
|
|
164
170
|
_, headers, = subject.call('PATH_INFO' => '/info.json')
|
165
171
|
expect(headers['Content-type']).to eq('application/json')
|
166
172
|
end
|
173
|
+
|
167
174
|
it 'is set for xml' do
|
168
175
|
_, headers, = subject.call('PATH_INFO' => '/info.xml')
|
169
176
|
expect(headers['Content-type']).to eq('application/xml')
|
170
177
|
end
|
178
|
+
|
171
179
|
it 'is set for txt' do
|
172
180
|
_, headers, = subject.call('PATH_INFO' => '/info.txt')
|
173
181
|
expect(headers['Content-type']).to eq('text/plain')
|
174
182
|
end
|
183
|
+
|
175
184
|
it 'is set for custom' do
|
176
185
|
subject.options[:content_types] = {}
|
177
186
|
subject.options[:content_types][:custom] = 'application/x-custom'
|
178
187
|
_, headers, = subject.call('PATH_INFO' => '/info.custom')
|
179
188
|
expect(headers['Content-type']).to eq('application/x-custom')
|
180
189
|
end
|
190
|
+
|
181
191
|
it 'is set for vendored with registered type' do
|
182
192
|
subject.options[:content_types] = {}
|
183
193
|
subject.options[:content_types][:custom] = 'application/vnd.test+json'
|
184
194
|
_, headers, = subject.call('PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')
|
185
195
|
expect(headers['Content-type']).to eq('application/vnd.test+json')
|
186
196
|
end
|
197
|
+
|
187
198
|
it 'is set to closest generic for custom vendored/versioned without registered type' do
|
188
199
|
_, headers, = subject.call('PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')
|
189
200
|
expect(headers['Content-type']).to eq('application/json')
|
@@ -198,13 +209,16 @@ describe Grape::Middleware::Formatter do
|
|
198
209
|
_, _, body = subject.call('PATH_INFO' => '/info.custom')
|
199
210
|
expect(read_chunks(body)).to eq(['CUSTOM FORMAT'])
|
200
211
|
end
|
212
|
+
|
201
213
|
context 'default' do
|
202
214
|
let(:body) { ['blah'] }
|
215
|
+
|
203
216
|
it 'uses default json formatter' do
|
204
217
|
_, _, body = subject.call('PATH_INFO' => '/info.json')
|
205
218
|
expect(read_chunks(body)).to eq(['["blah"]'])
|
206
219
|
end
|
207
220
|
end
|
221
|
+
|
208
222
|
it 'uses custom json formatter' do
|
209
223
|
subject.options[:formatters][:json] = ->(_obj, _env) { 'CUSTOM JSON FORMAT' }
|
210
224
|
_, _, body = subject.call('PATH_INFO' => '/info.json')
|
@@ -272,6 +286,7 @@ describe Grape::Middleware::Formatter do
|
|
272
286
|
|
273
287
|
context 'when body is nil' do
|
274
288
|
let(:io) { double }
|
289
|
+
|
275
290
|
before do
|
276
291
|
allow(io).to receive_message_chain(:rewind, :read).and_return(nil)
|
277
292
|
end
|
@@ -290,6 +305,7 @@ describe Grape::Middleware::Formatter do
|
|
290
305
|
|
291
306
|
context 'when body is empty' do
|
292
307
|
let(:io) { double }
|
308
|
+
|
293
309
|
before do
|
294
310
|
allow(io).to receive_message_chain(:rewind, :read).and_return('')
|
295
311
|
end
|
@@ -334,6 +350,7 @@ describe Grape::Middleware::Formatter do
|
|
334
350
|
expect(subject.env['rack.request.form_hash']['is_boolean']).to be true
|
335
351
|
expect(subject.env['rack.request.form_hash']['string']).to eq('thing')
|
336
352
|
end
|
353
|
+
|
337
354
|
it 'rewinds IO' do
|
338
355
|
io = StringIO.new('{"is_boolean":true,"string":"thing"}')
|
339
356
|
io.read
|
@@ -347,6 +364,7 @@ describe Grape::Middleware::Formatter do
|
|
347
364
|
expect(subject.env['rack.request.form_hash']['is_boolean']).to be true
|
348
365
|
expect(subject.env['rack.request.form_hash']['string']).to eq('thing')
|
349
366
|
end
|
367
|
+
|
350
368
|
it "parses the body from an xml #{method} and copies values into rack.request.from_hash" do
|
351
369
|
io = StringIO.new('<thing><name>Test</name></thing>')
|
352
370
|
subject.call(
|
@@ -362,6 +380,7 @@ describe Grape::Middleware::Formatter do
|
|
362
380
|
expect(subject.env['rack.request.form_hash']['thing']['name']['__content__']).to eq('Test')
|
363
381
|
end
|
364
382
|
end
|
383
|
+
|
365
384
|
[Rack::Request::FORM_DATA_MEDIA_TYPES, Rack::Request::PARSEABLE_DATA_MEDIA_TYPES].flatten.each do |content_type|
|
366
385
|
it "ignores #{content_type}" do
|
367
386
|
io = StringIO.new('name=Other+Test+Thing')
|
@@ -400,10 +419,12 @@ describe Grape::Middleware::Formatter do
|
|
400
419
|
end
|
401
420
|
end
|
402
421
|
let(:app) { ->(_env) { [200, {}, ['']] } }
|
422
|
+
|
403
423
|
before do
|
404
424
|
Grape::Formatter.register :invalid, InvalidFormatter
|
405
425
|
Grape::ContentTypes.register :invalid, 'application/x-invalid'
|
406
426
|
end
|
427
|
+
|
407
428
|
after do
|
408
429
|
Grape::ContentTypes.default_elements.delete(:invalid)
|
409
430
|
Grape::Formatter.default_elements.delete(:invalid)
|
@@ -418,7 +439,7 @@ describe Grape::Middleware::Formatter do
|
|
418
439
|
|
419
440
|
context 'custom parser raises exception and rescue options are enabled for backtrace and original_exception' do
|
420
441
|
it 'adds the backtrace and original_exception to the error output' do
|
421
|
-
subject =
|
442
|
+
subject = described_class.new(
|
422
443
|
app,
|
423
444
|
rescue_options: { backtrace: true, original_exception: true },
|
424
445
|
parsers: { json: ->(_object, _env) { raise StandardError, 'fail' } }
|
@@ -3,7 +3,8 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Globals do
|
6
|
-
subject {
|
6
|
+
subject { described_class.new(blank_app) }
|
7
|
+
|
7
8
|
before { allow(subject).to receive(:dup).and_return(subject) }
|
8
9
|
|
9
10
|
let(:blank_app) { ->(_env) { [200, {}, 'Hi there.'] } }
|
@@ -13,15 +14,17 @@ describe Grape::Middleware::Globals do
|
|
13
14
|
end
|
14
15
|
|
15
16
|
context 'environment' do
|
16
|
-
it '
|
17
|
+
it 'sets the grape.request environment' do
|
17
18
|
subject.call({})
|
18
19
|
expect(subject.env['grape.request']).to be_a(Grape::Request)
|
19
20
|
end
|
20
|
-
|
21
|
+
|
22
|
+
it 'sets the grape.request.headers environment' do
|
21
23
|
subject.call({})
|
22
24
|
expect(subject.env['grape.request.headers']).to be_a(Hash)
|
23
25
|
end
|
24
|
-
|
26
|
+
|
27
|
+
it 'sets the grape.request.params environment' do
|
25
28
|
subject.call('QUERY_STRING' => 'test=1', 'rack.input' => StringIO.new)
|
26
29
|
expect(subject.env['grape.request.params']).to be_a(Hash)
|
27
30
|
end
|
@@ -17,11 +17,11 @@ describe Grape::Middleware::Stack do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
subject { described_class.new }
|
21
|
+
|
20
22
|
let(:proc) { -> {} }
|
21
23
|
let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
|
22
24
|
|
23
|
-
subject { Grape::Middleware::Stack.new }
|
24
|
-
|
25
25
|
before do
|
26
26
|
subject.use StackSpec::FooMiddleware
|
27
27
|
end
|
@@ -29,20 +29,20 @@ describe Grape::Middleware::Stack do
|
|
29
29
|
describe '#use' do
|
30
30
|
it 'pushes a middleware class onto the stack' do
|
31
31
|
expect { subject.use StackSpec::BarMiddleware }
|
32
|
-
.to change
|
32
|
+
.to change(subject, :size).by(1)
|
33
33
|
expect(subject.last).to eq(StackSpec::BarMiddleware)
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'pushes a middleware class with arguments onto the stack' do
|
37
37
|
expect { subject.use StackSpec::BarMiddleware, false, my_arg: 42 }
|
38
|
-
.to change
|
38
|
+
.to change(subject, :size).by(1)
|
39
39
|
expect(subject.last).to eq(StackSpec::BarMiddleware)
|
40
40
|
expect(subject.last.args).to eq([false, { my_arg: 42 }])
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'pushes a middleware class with block arguments onto the stack' do
|
44
44
|
expect { subject.use StackSpec::BlockMiddleware, &proc }
|
45
|
-
.to change
|
45
|
+
.to change(subject, :size).by(1)
|
46
46
|
expect(subject.last).to eq(StackSpec::BlockMiddleware)
|
47
47
|
expect(subject.last.args).to eq([])
|
48
48
|
expect(subject.last.block).to eq(proc)
|
@@ -52,7 +52,7 @@ describe Grape::Middleware::Stack do
|
|
52
52
|
describe '#insert' do
|
53
53
|
it 'inserts a middleware class at the integer index' do
|
54
54
|
expect { subject.insert 0, StackSpec::BarMiddleware }
|
55
|
-
.to change
|
55
|
+
.to change(subject, :size).by(1)
|
56
56
|
expect(subject[0]).to eq(StackSpec::BarMiddleware)
|
57
57
|
expect(subject[1]).to eq(StackSpec::FooMiddleware)
|
58
58
|
end
|
@@ -61,7 +61,7 @@ describe Grape::Middleware::Stack do
|
|
61
61
|
describe '#insert_before' do
|
62
62
|
it 'inserts a middleware before another middleware class' do
|
63
63
|
expect { subject.insert_before StackSpec::FooMiddleware, StackSpec::BarMiddleware }
|
64
|
-
.to change
|
64
|
+
.to change(subject, :size).by(1)
|
65
65
|
expect(subject[0]).to eq(StackSpec::BarMiddleware)
|
66
66
|
expect(subject[1]).to eq(StackSpec::FooMiddleware)
|
67
67
|
end
|
@@ -70,7 +70,7 @@ describe Grape::Middleware::Stack do
|
|
70
70
|
subject.use Class.new(StackSpec::BlockMiddleware)
|
71
71
|
|
72
72
|
expect { subject.insert_before StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
|
73
|
-
.to change
|
73
|
+
.to change(subject, :size).by(1)
|
74
74
|
|
75
75
|
expect(subject[1]).to eq(StackSpec::BarMiddleware)
|
76
76
|
expect(subject[2]).to eq(StackSpec::BlockMiddleware)
|
@@ -85,7 +85,7 @@ describe Grape::Middleware::Stack do
|
|
85
85
|
describe '#insert_after' do
|
86
86
|
it 'inserts a middleware after another middleware class' do
|
87
87
|
expect { subject.insert_after StackSpec::FooMiddleware, StackSpec::BarMiddleware }
|
88
|
-
.to change
|
88
|
+
.to change(subject, :size).by(1)
|
89
89
|
expect(subject[1]).to eq(StackSpec::BarMiddleware)
|
90
90
|
expect(subject[0]).to eq(StackSpec::FooMiddleware)
|
91
91
|
end
|
@@ -94,7 +94,7 @@ describe Grape::Middleware::Stack do
|
|
94
94
|
subject.use Class.new(StackSpec::BlockMiddleware)
|
95
95
|
|
96
96
|
expect { subject.insert_after StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
|
97
|
-
.to change
|
97
|
+
.to change(subject, :size).by(1)
|
98
98
|
|
99
99
|
expect(subject[1]).to eq(StackSpec::BlockMiddleware)
|
100
100
|
expect(subject[2]).to eq(StackSpec::BarMiddleware)
|
@@ -109,7 +109,7 @@ describe Grape::Middleware::Stack do
|
|
109
109
|
describe '#merge_with' do
|
110
110
|
it 'applies a collection of operations and middlewares' do
|
111
111
|
expect { subject.merge_with(others) }
|
112
|
-
.to change
|
112
|
+
.to change(subject, :size).by(2)
|
113
113
|
expect(subject[0]).to eq(StackSpec::FooMiddleware)
|
114
114
|
expect(subject[1]).to eq(StackSpec::BlockMiddleware)
|
115
115
|
expect(subject[2]).to eq(StackSpec::BarMiddleware)
|
@@ -3,8 +3,9 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
6
|
+
subject { described_class.new(app, **(@options || {})) }
|
7
|
+
|
6
8
|
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
subject { Grape::Middleware::Versioner::AcceptVersionHeader.new(app, **(@options || {})) }
|
8
9
|
|
9
10
|
before do
|
10
11
|
@options = {
|
@@ -3,8 +3,9 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Versioner::Header do
|
6
|
+
subject { described_class.new(app, **(@options || {})) }
|
7
|
+
|
6
8
|
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
subject { Grape::Middleware::Versioner::Header.new(app, **(@options || {})) }
|
8
9
|
|
9
10
|
before do
|
10
11
|
@options = {
|
@@ -47,7 +48,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
47
48
|
|
48
49
|
it 'is nil if not provided' do
|
49
50
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
50
|
-
expect(env['api.format']).to
|
51
|
+
expect(env['api.format']).to be nil
|
51
52
|
expect(status).to eq(200)
|
52
53
|
end
|
53
54
|
|
@@ -65,7 +66,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
65
66
|
|
66
67
|
it 'is nil if not provided' do
|
67
68
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
68
|
-
expect(env['api.format']).to
|
69
|
+
expect(env['api.format']).to be nil
|
69
70
|
expect(status).to eq(200)
|
70
71
|
end
|
71
72
|
end
|
@@ -90,7 +91,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
90
91
|
.to raise_exception do |exception|
|
91
92
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
92
93
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
93
|
-
expect(exception.status).to
|
94
|
+
expect(exception.status).to be 406
|
94
95
|
expect(exception.message).to include 'API vendor not found'
|
95
96
|
end
|
96
97
|
end
|
@@ -117,7 +118,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
117
118
|
.to raise_exception do |exception|
|
118
119
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
119
120
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
120
|
-
expect(exception.status).to
|
121
|
+
expect(exception.status).to be 406
|
121
122
|
expect(exception.message).to include('API vendor not found')
|
122
123
|
end
|
123
124
|
end
|
@@ -145,7 +146,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
145
146
|
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
|
146
147
|
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
147
148
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
148
|
-
expect(exception.status).to
|
149
|
+
expect(exception.status).to be 406
|
149
150
|
expect(exception.message).to include('API version not found')
|
150
151
|
end
|
151
152
|
end
|
@@ -178,7 +179,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
178
179
|
expect { subject.call({}).last }.to raise_exception do |exception|
|
179
180
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
180
181
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
181
|
-
expect(exception.status).to
|
182
|
+
expect(exception.status).to be 406
|
182
183
|
expect(exception.message).to include('Accept header must be set.')
|
183
184
|
end
|
184
185
|
end
|
@@ -187,7 +188,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
187
188
|
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
188
189
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
189
190
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
190
|
-
expect(exception.status).to
|
191
|
+
expect(exception.status).to be 406
|
191
192
|
expect(exception.message).to include('Accept header must be set.')
|
192
193
|
end
|
193
194
|
end
|
@@ -208,7 +209,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
208
209
|
expect { subject.call({}).last }.to raise_exception do |exception|
|
209
210
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
210
211
|
expect(exception.headers).to eql({})
|
211
|
-
expect(exception.status).to
|
212
|
+
expect(exception.status).to be 406
|
212
213
|
expect(exception.message).to include('Accept header must be set.')
|
213
214
|
end
|
214
215
|
end
|
@@ -218,7 +219,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
218
219
|
.to raise_exception do |exception|
|
219
220
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
220
221
|
expect(exception.headers).to eql({})
|
221
|
-
expect(exception.status).to
|
222
|
+
expect(exception.status).to be 406
|
222
223
|
expect(exception.message).to include('API vendor or version not found.')
|
223
224
|
end
|
224
225
|
end
|
@@ -227,7 +228,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
227
228
|
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
228
229
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
229
230
|
expect(exception.headers).to eql({})
|
230
|
-
expect(exception.status).to
|
231
|
+
expect(exception.status).to be 406
|
231
232
|
expect(exception.message).to include('Accept header must be set.')
|
232
233
|
end
|
233
234
|
end
|
@@ -237,7 +238,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
237
238
|
.to raise_exception do |exception|
|
238
239
|
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
239
240
|
expect(exception.headers).to eql({})
|
240
|
-
expect(exception.status).to
|
241
|
+
expect(exception.status).to be 406
|
241
242
|
expect(exception.message).to include('API vendor or version not found.')
|
242
243
|
end
|
243
244
|
end
|
@@ -264,7 +265,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
264
265
|
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
|
265
266
|
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
266
267
|
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
267
|
-
expect(exception.status).to
|
268
|
+
expect(exception.status).to be 406
|
268
269
|
expect(exception.message).to include('API version not found')
|
269
270
|
end
|
270
271
|
end
|
@@ -3,9 +3,10 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Versioner::Param do
|
6
|
+
subject { described_class.new(app, **options) }
|
7
|
+
|
6
8
|
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
9
|
let(:options) { {} }
|
8
|
-
subject { Grape::Middleware::Versioner::Param.new(app, **options) }
|
9
10
|
|
10
11
|
it 'sets the API version based on the default param (apiver)' do
|
11
12
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
@@ -26,10 +27,12 @@ describe Grape::Middleware::Versioner::Param do
|
|
26
27
|
|
27
28
|
context 'with specified parameter name' do
|
28
29
|
let(:options) { { version_options: { parameter: 'v' } } }
|
30
|
+
|
29
31
|
it 'sets the API version based on the custom parameter name' do
|
30
32
|
env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
|
31
33
|
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
32
34
|
end
|
35
|
+
|
33
36
|
it 'does not set the API version based on the default param' do
|
34
37
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
35
38
|
expect(subject.call(env)[1]['api.version']).to be_nil
|
@@ -38,10 +41,12 @@ describe Grape::Middleware::Versioner::Param do
|
|
38
41
|
|
39
42
|
context 'with specified versions' do
|
40
43
|
let(:options) { { versions: %w[v1 v2] } }
|
44
|
+
|
41
45
|
it 'throws an error if a non-allowed version is specified' do
|
42
46
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
|
43
47
|
expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
|
44
48
|
end
|
49
|
+
|
45
50
|
it 'allows versions that have been specified' do
|
46
51
|
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
47
52
|
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
@@ -55,6 +60,7 @@ describe Grape::Middleware::Versioner::Param do
|
|
55
60
|
version_options: { using: :header }
|
56
61
|
}
|
57
62
|
end
|
63
|
+
|
58
64
|
it 'returns a 200 (matches the first version found)' do
|
59
65
|
env = Rack::MockRequest.env_for('/awesome', params: {})
|
60
66
|
expect(subject.call(env).first).to eq(200)
|
@@ -3,9 +3,10 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Middleware::Versioner::Path do
|
6
|
+
subject { described_class.new(app, **options) }
|
7
|
+
|
6
8
|
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
9
|
let(:options) { {} }
|
8
|
-
subject { Grape::Middleware::Versioner::Path.new(app, **options) }
|
9
10
|
|
10
11
|
it 'sets the API version based on the first path' do
|
11
12
|
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
@@ -21,6 +22,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
21
22
|
|
22
23
|
context 'with a pattern' do
|
23
24
|
let(:options) { { pattern: /v./i } }
|
25
|
+
|
24
26
|
it 'sets the version if it matches' do
|
25
27
|
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
26
28
|
end
|
@@ -46,6 +48,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
46
48
|
|
47
49
|
context 'with prefix, but requested version is not matched' do
|
48
50
|
let(:options) { { prefix: '/v1', pattern: /v./i } }
|
51
|
+
|
49
52
|
it 'recognizes potential version' do
|
50
53
|
expect(subject.call('PATH_INFO' => '/v3/foo').last).to eq('v3')
|
51
54
|
end
|
@@ -53,6 +56,7 @@ describe Grape::Middleware::Versioner::Path do
|
|
53
56
|
|
54
57
|
context 'with mount path' do
|
55
58
|
let(:options) { { mount_path: '/mounted', versions: [:v1] } }
|
59
|
+
|
56
60
|
it 'recognizes potential version' do
|
57
61
|
expect(subject.call('PATH_INFO' => '/mounted/v1/foo').last).to eq('v1')
|
58
62
|
end
|
data/spec/grape/parser_spec.rb
CHANGED
@@ -26,6 +26,7 @@ describe Grape::Parser do
|
|
26
26
|
|
27
27
|
context 'with :parsers option' do
|
28
28
|
let(:parsers) { { customized: Class.new } }
|
29
|
+
|
29
30
|
it 'includes passed :parsers values' do
|
30
31
|
expect(subject.parsers(parsers: parsers)).to include(parsers)
|
31
32
|
end
|
@@ -33,7 +34,9 @@ describe Grape::Parser do
|
|
33
34
|
|
34
35
|
context 'with added parser by using `register` keyword' do
|
35
36
|
let(:added_parser) { Class.new }
|
37
|
+
|
36
38
|
before { subject.register :added, added_parser }
|
39
|
+
|
37
40
|
it 'includes added parser' do
|
38
41
|
expect(subject.parsers(**{})).to include(added: added_parser)
|
39
42
|
end
|
@@ -54,6 +57,7 @@ describe Grape::Parser do
|
|
54
57
|
|
55
58
|
context 'when parser is available' do
|
56
59
|
before { subject.register :customized_json, Grape::Parser::Json }
|
60
|
+
|
57
61
|
it 'returns registered parser if available' do
|
58
62
|
expect(subject.parser_for(:customized_json)).to eq(Grape::Parser::Json)
|
59
63
|
end
|