grape 1.5.2 → 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 +47 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +33 -3
- data/UPGRADING.md +71 -2
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +13 -17
- data/lib/grape/api.rb +18 -13
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/desc.rb +3 -5
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +7 -5
- data/lib/grape/dsl/inside_route.rb +17 -8
- data/lib/grape/dsl/middleware.rb +4 -4
- data/lib/grape/dsl/parameters.rb +3 -3
- data/lib/grape/dsl/request_response.rb +9 -6
- data/lib/grape/dsl/routing.rb +2 -2
- data/lib/grape/dsl/settings.rb +5 -5
- data/lib/grape/endpoint.rb +21 -36
- data/lib/grape/error_formatter/json.rb +2 -6
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/validation.rb +1 -2
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +3 -1
- data/lib/grape/middleware/formatter.rb +4 -4
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +3 -0
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +6 -0
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/lazy_value.rb +3 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/params_scope.rb +88 -55
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +3 -3
- data/lib/grape/validations/validators/all_or_none.rb +8 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +6 -8
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
- data/lib/grape/validations/validators/base.rb +75 -70
- data/lib/grape/validations/validators/coerce.rb +63 -79
- data/lib/grape/validations/validators/default.rb +37 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
- data/lib/grape/validations/validators/presence.rb +7 -4
- data/lib/grape/validations/validators/regexp.rb +8 -5
- data/lib/grape/validations/validators/same_as.rb +18 -15
- data/lib/grape/validations/validators/values.rb +61 -56
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +4 -1
- data/spec/grape/api/custom_validations_spec.rb +77 -45
- 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/routes_with_requirements_spec.rb +8 -8
- 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 +510 -220
- data/spec/grape/dsl/callbacks_spec.rb +2 -1
- 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 +2 -1
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +10 -7
- data/spec/grape/endpoint/declared_spec.rb +259 -12
- data/spec/grape/endpoint_spec.rb +77 -55
- data/spec/grape/entity_spec.rb +22 -22
- 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 +15 -6
- 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 +2 -2
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +27 -6
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +14 -12
- 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 +46 -10
- data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -1
- data/spec/grape/validations/types/primitive_coercer_spec.rb +4 -4
- 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 +99 -22
- 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 +3 -3
- 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 +183 -178
- data/spec/grape/validations_spec.rb +99 -58
- 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 +12 -9
- data/spec/spec_helper.rb +12 -2
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- metadata +102 -101
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -10,32 +10,32 @@ describe Grape::Endpoint do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe '.before_each' do
|
13
|
-
after {
|
13
|
+
after { described_class.before_each.clear }
|
14
14
|
|
15
15
|
it 'is settable via block' do
|
16
16
|
block = ->(_endpoint) { 'noop' }
|
17
|
-
|
18
|
-
expect(
|
17
|
+
described_class.before_each(&block)
|
18
|
+
expect(described_class.before_each.first).to eq(block)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'is settable via reference' do
|
22
22
|
block = ->(_endpoint) { 'noop' }
|
23
|
-
|
24
|
-
expect(
|
23
|
+
described_class.before_each block
|
24
|
+
expect(described_class.before_each.first).to eq(block)
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'is able to override a helper' do
|
28
28
|
subject.get('/') { current_user }
|
29
29
|
expect { get '/' }.to raise_error(NameError)
|
30
30
|
|
31
|
-
|
31
|
+
described_class.before_each do |endpoint|
|
32
32
|
allow(endpoint).to receive(:current_user).and_return('Bob')
|
33
33
|
end
|
34
34
|
|
35
35
|
get '/'
|
36
36
|
expect(last_response.body).to eq('Bob')
|
37
37
|
|
38
|
-
|
38
|
+
described_class.before_each(nil)
|
39
39
|
expect { get '/' }.to raise_error(NameError)
|
40
40
|
end
|
41
41
|
|
@@ -46,18 +46,18 @@ describe Grape::Endpoint do
|
|
46
46
|
end
|
47
47
|
expect { get '/' }.to raise_error(NameError)
|
48
48
|
|
49
|
-
|
49
|
+
described_class.before_each do |endpoint|
|
50
50
|
allow(endpoint).to receive(:current_user).and_return('Bob')
|
51
51
|
end
|
52
52
|
|
53
|
-
|
53
|
+
described_class.before_each do |endpoint|
|
54
54
|
allow(endpoint).to receive(:authenticate_user!).and_return(true)
|
55
55
|
end
|
56
56
|
|
57
57
|
get '/'
|
58
58
|
expect(last_response.body).to eq('Bob')
|
59
59
|
|
60
|
-
|
60
|
+
described_class.before_each(nil)
|
61
61
|
expect { get '/' }.to raise_error(NameError)
|
62
62
|
end
|
63
63
|
end
|
@@ -66,7 +66,7 @@ describe Grape::Endpoint do
|
|
66
66
|
it 'takes a settings stack, options, and a block' do
|
67
67
|
p = proc {}
|
68
68
|
expect do
|
69
|
-
|
69
|
+
described_class.new(Grape::Util::InheritableSetting.new, {
|
70
70
|
path: '/',
|
71
71
|
method: :get
|
72
72
|
}, &p)
|
@@ -77,7 +77,7 @@ describe Grape::Endpoint do
|
|
77
77
|
it 'sets itself in the env upon call' do
|
78
78
|
subject.get('/') { 'Hello world.' }
|
79
79
|
get '/'
|
80
|
-
expect(last_request.env['api.endpoint']).to be_kind_of(
|
80
|
+
expect(last_request.env['api.endpoint']).to be_kind_of(described_class)
|
81
81
|
end
|
82
82
|
|
83
83
|
describe '#status' do
|
@@ -137,6 +137,7 @@ describe Grape::Endpoint do
|
|
137
137
|
headers.to_json
|
138
138
|
end
|
139
139
|
end
|
140
|
+
|
140
141
|
it 'includes request headers' do
|
141
142
|
get '/headers'
|
142
143
|
expect(JSON.parse(last_response.body)).to eq(
|
@@ -144,13 +145,15 @@ describe Grape::Endpoint do
|
|
144
145
|
'Cookie' => ''
|
145
146
|
)
|
146
147
|
end
|
148
|
+
|
147
149
|
it 'includes additional request headers' do
|
148
150
|
get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
|
149
151
|
expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
|
150
152
|
end
|
153
|
+
|
151
154
|
it 'includes headers passed as symbols' do
|
152
155
|
env = Rack::MockRequest.env_for('/headers')
|
153
|
-
env[
|
156
|
+
env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
|
154
157
|
body = read_chunks(subject.call(env)[2]).join
|
155
158
|
expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
|
156
159
|
end
|
@@ -212,10 +215,10 @@ describe Grape::Endpoint do
|
|
212
215
|
end
|
213
216
|
get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
|
214
217
|
expect(last_response.body).to eq('3')
|
215
|
-
cookies =
|
218
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
|
216
219
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
217
220
|
[cookie.name, cookie]
|
218
|
-
end
|
221
|
+
end.to_h
|
219
222
|
expect(cookies.size).to eq(2)
|
220
223
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
221
224
|
cookie = cookies[cookie_name]
|
@@ -236,10 +239,10 @@ describe Grape::Endpoint do
|
|
236
239
|
end
|
237
240
|
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
|
238
241
|
expect(last_response.body).to eq('3')
|
239
|
-
cookies =
|
242
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
|
240
243
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
241
244
|
[cookie.name, cookie]
|
242
|
-
end
|
245
|
+
end.to_h
|
243
246
|
expect(cookies.size).to eq(2)
|
244
247
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
245
248
|
cookie = cookies[cookie_name]
|
@@ -253,7 +256,7 @@ describe Grape::Endpoint do
|
|
253
256
|
|
254
257
|
describe '#params' do
|
255
258
|
context 'default class' do
|
256
|
-
it '
|
259
|
+
it 'is a ActiveSupport::HashWithIndifferentAccess' do
|
257
260
|
subject.get '/foo' do
|
258
261
|
params.class
|
259
262
|
end
|
@@ -339,7 +342,7 @@ describe Grape::Endpoint do
|
|
339
342
|
end
|
340
343
|
|
341
344
|
context 'namespace requirements' do
|
342
|
-
before
|
345
|
+
before do
|
343
346
|
subject.namespace :outer, requirements: { person_email: /abc@(.*).com/ } do
|
344
347
|
get('/:person_email') do
|
345
348
|
params[:person_email]
|
@@ -358,7 +361,7 @@ describe Grape::Endpoint do
|
|
358
361
|
expect(last_response.body).to eq('abc@example.com')
|
359
362
|
end
|
360
363
|
|
361
|
-
it "
|
364
|
+
it "overrides outer namespace's requirements" do
|
362
365
|
get '/outer/inner/someone@testing.wrong/test/1'
|
363
366
|
expect(last_response.status).to eq(404)
|
364
367
|
|
@@ -370,7 +373,7 @@ describe Grape::Endpoint do
|
|
370
373
|
end
|
371
374
|
|
372
375
|
context 'from body parameters' do
|
373
|
-
before
|
376
|
+
before do
|
374
377
|
subject.post '/request_body' do
|
375
378
|
params[:user]
|
376
379
|
end
|
@@ -420,6 +423,19 @@ describe Grape::Endpoint do
|
|
420
423
|
expect(last_response.status).to eq(201)
|
421
424
|
expect(last_response.body).to eq('Bob')
|
422
425
|
end
|
426
|
+
|
427
|
+
# Rack swallowed this error until v2.2.0
|
428
|
+
it 'returns a 400 if given an invalid multipart body', if: Gem::Version.new(Rack.release) >= Gem::Version.new('2.2.0') do
|
429
|
+
subject.params do
|
430
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
431
|
+
end
|
432
|
+
subject.post '/upload' do
|
433
|
+
params[:file][:filename]
|
434
|
+
end
|
435
|
+
post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
|
436
|
+
expect(last_response.status).to eq(400)
|
437
|
+
expect(last_response.body).to eq('Empty message body supplied with multipart/form-data; boundary=foobar content-type')
|
438
|
+
end
|
423
439
|
end
|
424
440
|
|
425
441
|
it 'responds with a 415 for an unsupported content-type' do
|
@@ -456,11 +472,11 @@ describe Grape::Endpoint do
|
|
456
472
|
post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
|
457
473
|
end
|
458
474
|
|
459
|
-
it '
|
475
|
+
it 'does not response with 406 for same type without params' do
|
460
476
|
expect(last_response.status).not_to be 406
|
461
477
|
end
|
462
478
|
|
463
|
-
it '
|
479
|
+
it 'responses with given content type in headers' do
|
464
480
|
expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
|
465
481
|
end
|
466
482
|
end
|
@@ -696,16 +712,18 @@ describe Grape::Endpoint do
|
|
696
712
|
describe '.generate_api_method' do
|
697
713
|
it 'raises NameError if the method name is already in use' do
|
698
714
|
expect do
|
699
|
-
|
715
|
+
described_class.generate_api_method('version', &proc {})
|
700
716
|
end.to raise_error(NameError)
|
701
717
|
end
|
718
|
+
|
702
719
|
it 'raises ArgumentError if a block is not given' do
|
703
720
|
expect do
|
704
|
-
|
721
|
+
described_class.generate_api_method('GET without a block method')
|
705
722
|
end.to raise_error(ArgumentError)
|
706
723
|
end
|
724
|
+
|
707
725
|
it 'returns a Proc' do
|
708
|
-
expect(
|
726
|
+
expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
|
709
727
|
end
|
710
728
|
end
|
711
729
|
|
@@ -764,7 +782,7 @@ describe Grape::Endpoint do
|
|
764
782
|
end
|
765
783
|
|
766
784
|
get '/error_filters'
|
767
|
-
expect(last_response.status).to
|
785
|
+
expect(last_response.status).to be 500
|
768
786
|
expect(called).to match_array %w[before before_validation]
|
769
787
|
end
|
770
788
|
|
@@ -773,8 +791,11 @@ describe Grape::Endpoint do
|
|
773
791
|
subject.before { called << 'parent' }
|
774
792
|
subject.namespace :parent do
|
775
793
|
before { called << 'prior' }
|
794
|
+
|
776
795
|
before { error! :oops, 500 }
|
796
|
+
|
777
797
|
before { called << 'subsequent' }
|
798
|
+
|
778
799
|
get :hello do
|
779
800
|
called << :endpoint
|
780
801
|
'Hello!'
|
@@ -782,7 +803,7 @@ describe Grape::Endpoint do
|
|
782
803
|
end
|
783
804
|
|
784
805
|
get '/parent/hello'
|
785
|
-
expect(last_response.status).to
|
806
|
+
expect(last_response.status).to be 500
|
786
807
|
expect(called).to match_array %w[parent prior]
|
787
808
|
end
|
788
809
|
end
|
@@ -793,19 +814,19 @@ describe Grape::Endpoint do
|
|
793
814
|
it 'allows for the anchoring option with a delete method' do
|
794
815
|
subject.send(:delete, '/example', anchor: true) {}
|
795
816
|
send(:delete, '/example/and/some/more')
|
796
|
-
expect(last_response.status).to
|
817
|
+
expect(last_response.status).to be 404
|
797
818
|
end
|
798
819
|
|
799
820
|
it 'anchors paths by default for the delete method' do
|
800
821
|
subject.send(:delete, '/example') {}
|
801
822
|
send(:delete, '/example/and/some/more')
|
802
|
-
expect(last_response.status).to
|
823
|
+
expect(last_response.status).to be 404
|
803
824
|
end
|
804
825
|
|
805
826
|
it 'responds to /example/and/some/more for the non-anchored delete method' do
|
806
827
|
subject.send(:delete, '/example', anchor: false) {}
|
807
828
|
send(:delete, '/example/and/some/more')
|
808
|
-
expect(last_response.status).to
|
829
|
+
expect(last_response.status).to be 204
|
809
830
|
expect(last_response.body).to be_empty
|
810
831
|
end
|
811
832
|
end
|
@@ -817,7 +838,7 @@ describe Grape::Endpoint do
|
|
817
838
|
body 'deleted'
|
818
839
|
end
|
819
840
|
send(:delete, '/example/and/some/more')
|
820
|
-
expect(last_response.status).to
|
841
|
+
expect(last_response.status).to be 200
|
821
842
|
expect(last_response.body).not_to be_empty
|
822
843
|
end
|
823
844
|
end
|
@@ -826,7 +847,7 @@ describe Grape::Endpoint do
|
|
826
847
|
it 'responds to /example delete method' do
|
827
848
|
subject.delete(:example) { 'deleted' }
|
828
849
|
delete '/example'
|
829
|
-
expect(last_response.status).to
|
850
|
+
expect(last_response.status).to be 200
|
830
851
|
expect(last_response.body).not_to be_empty
|
831
852
|
end
|
832
853
|
end
|
@@ -835,7 +856,7 @@ describe Grape::Endpoint do
|
|
835
856
|
it 'responds to /example delete method' do
|
836
857
|
subject.delete(:example) { nil }
|
837
858
|
delete '/example'
|
838
|
-
expect(last_response.status).to
|
859
|
+
expect(last_response.status).to be 204
|
839
860
|
expect(last_response.body).to be_empty
|
840
861
|
end
|
841
862
|
end
|
@@ -844,7 +865,7 @@ describe Grape::Endpoint do
|
|
844
865
|
it 'responds to /example delete method' do
|
845
866
|
subject.delete(:example) { '' }
|
846
867
|
delete '/example'
|
847
|
-
expect(last_response.status).to
|
868
|
+
expect(last_response.status).to be 204
|
848
869
|
expect(last_response.body).to be_empty
|
849
870
|
end
|
850
871
|
end
|
@@ -856,7 +877,7 @@ describe Grape::Endpoint do
|
|
856
877
|
verb
|
857
878
|
end
|
858
879
|
send(verb, '/example/and/some/more')
|
859
|
-
expect(last_response.status).to
|
880
|
+
expect(last_response.status).to be 404
|
860
881
|
end
|
861
882
|
|
862
883
|
it "anchors paths by default for the #{verb.upcase} method" do
|
@@ -864,7 +885,7 @@ describe Grape::Endpoint do
|
|
864
885
|
verb
|
865
886
|
end
|
866
887
|
send(verb, '/example/and/some/more')
|
867
|
-
expect(last_response.status).to
|
888
|
+
expect(last_response.status).to be 404
|
868
889
|
end
|
869
890
|
|
870
891
|
it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
|
@@ -887,8 +908,9 @@ describe Grape::Endpoint do
|
|
887
908
|
get '/url'
|
888
909
|
expect(last_response.body).to eq('http://example.org/url')
|
889
910
|
end
|
911
|
+
|
890
912
|
['v1', :v1].each do |version|
|
891
|
-
it "
|
913
|
+
it "includes version #{version}" do
|
892
914
|
subject.version version, using: :path
|
893
915
|
subject.get('/url') do
|
894
916
|
request.url
|
@@ -897,7 +919,7 @@ describe Grape::Endpoint do
|
|
897
919
|
expect(last_response.body).to eq("http://example.org/#{version}/url")
|
898
920
|
end
|
899
921
|
end
|
900
|
-
it '
|
922
|
+
it 'includes prefix' do
|
901
923
|
subject.version 'v1', using: :path
|
902
924
|
subject.prefix 'api'
|
903
925
|
subject.get('/url') do
|
@@ -987,26 +1009,26 @@ describe Grape::Endpoint do
|
|
987
1009
|
|
988
1010
|
# In order that the events finalized (time each block ended)
|
989
1011
|
expect(@events).to contain_exactly(
|
990
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1012
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
991
1013
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
992
1014
|
type: :before }),
|
993
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1015
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
994
1016
|
filters: [],
|
995
1017
|
type: :before_validation }),
|
996
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1018
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
997
1019
|
validators: [],
|
998
1020
|
request: a_kind_of(Grape::Request) }),
|
999
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1021
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1000
1022
|
filters: [],
|
1001
1023
|
type: :after_validation }),
|
1002
|
-
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(
|
1003
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1024
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1025
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1004
1026
|
filters: [],
|
1005
1027
|
type: :after }),
|
1006
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1028
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1007
1029
|
filters: [],
|
1008
1030
|
type: :finally }),
|
1009
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1031
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1010
1032
|
env: an_instance_of(Hash) }),
|
1011
1033
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
1012
1034
|
formatter: a_kind_of(Module) })
|
@@ -1014,25 +1036,25 @@ describe Grape::Endpoint do
|
|
1014
1036
|
|
1015
1037
|
# In order that events were initialized
|
1016
1038
|
expect(@events.sort_by(&:time)).to contain_exactly(
|
1017
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1039
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1018
1040
|
env: an_instance_of(Hash) }),
|
1019
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1041
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1020
1042
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1021
1043
|
type: :before }),
|
1022
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1044
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1023
1045
|
filters: [],
|
1024
1046
|
type: :before_validation }),
|
1025
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1047
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
1026
1048
|
validators: [],
|
1027
1049
|
request: a_kind_of(Grape::Request) }),
|
1028
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1050
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1029
1051
|
filters: [],
|
1030
1052
|
type: :after_validation }),
|
1031
|
-
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(
|
1032
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1053
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1054
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1033
1055
|
filters: [],
|
1034
1056
|
type: :after }),
|
1035
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1057
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1036
1058
|
filters: [],
|
1037
1059
|
type: :finally }),
|
1038
1060
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
data/spec/grape/entity_spec.rb
CHANGED
@@ -32,7 +32,7 @@ describe Grape::Entity do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'pulls a representation from the class options if it exists' do
|
35
|
-
entity = Class.new(
|
35
|
+
entity = Class.new(described_class)
|
36
36
|
allow(entity).to receive(:represent).and_return('Hiya')
|
37
37
|
|
38
38
|
subject.represent Object, with: entity
|
@@ -44,7 +44,7 @@ describe Grape::Entity do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'pulls a representation from the class options if the presented object is a collection of objects' do
|
47
|
-
entity = Class.new(
|
47
|
+
entity = Class.new(described_class)
|
48
48
|
allow(entity).to receive(:represent).and_return('Hiya')
|
49
49
|
|
50
50
|
module EntitySpec
|
@@ -75,7 +75,7 @@ describe Grape::Entity do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'pulls a representation from the class ancestor if it exists' do
|
78
|
-
entity = Class.new(
|
78
|
+
entity = Class.new(described_class)
|
79
79
|
allow(entity).to receive(:represent).and_return('Hiya')
|
80
80
|
|
81
81
|
subclass = Class.new(Object)
|
@@ -90,7 +90,7 @@ describe Grape::Entity do
|
|
90
90
|
|
91
91
|
it 'automatically uses Klass::Entity if that exists' do
|
92
92
|
some_model = Class.new
|
93
|
-
entity = Class.new(
|
93
|
+
entity = Class.new(described_class)
|
94
94
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
95
95
|
|
96
96
|
some_model.const_set :Entity, entity
|
@@ -104,7 +104,7 @@ describe Grape::Entity do
|
|
104
104
|
|
105
105
|
it 'automatically uses Klass::Entity based on the first object in the collection being presented' do
|
106
106
|
some_model = Class.new
|
107
|
-
entity = Class.new(
|
107
|
+
entity = Class.new(described_class)
|
108
108
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
109
109
|
|
110
110
|
some_model.const_set :Entity, entity
|
@@ -117,7 +117,7 @@ describe Grape::Entity do
|
|
117
117
|
end
|
118
118
|
|
119
119
|
it 'does not run autodetection for Entity when explicitly provided' do
|
120
|
-
entity = Class.new(
|
120
|
+
entity = Class.new(described_class)
|
121
121
|
some_array = []
|
122
122
|
|
123
123
|
subject.get '/example' do
|
@@ -129,7 +129,7 @@ describe Grape::Entity do
|
|
129
129
|
end
|
130
130
|
|
131
131
|
it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do
|
132
|
-
entity = Class.new(
|
132
|
+
entity = Class.new(described_class)
|
133
133
|
some_relation = Class.new
|
134
134
|
some_model = Class.new
|
135
135
|
|
@@ -173,7 +173,7 @@ describe Grape::Entity do
|
|
173
173
|
|
174
174
|
%i[json serializable_hash].each do |format|
|
175
175
|
it "presents with #{format}" do
|
176
|
-
entity = Class.new(
|
176
|
+
entity = Class.new(described_class)
|
177
177
|
entity.root 'examples', 'example'
|
178
178
|
entity.expose :id
|
179
179
|
|
@@ -195,7 +195,7 @@ describe Grape::Entity do
|
|
195
195
|
end
|
196
196
|
|
197
197
|
it "presents with #{format} collection" do
|
198
|
-
entity = Class.new(
|
198
|
+
entity = Class.new(described_class)
|
199
199
|
entity.root 'examples', 'example'
|
200
200
|
entity.expose :id
|
201
201
|
|
@@ -219,7 +219,7 @@ describe Grape::Entity do
|
|
219
219
|
end
|
220
220
|
|
221
221
|
it 'presents with xml' do
|
222
|
-
entity = Class.new(
|
222
|
+
entity = Class.new(described_class)
|
223
223
|
entity.root 'examples', 'example'
|
224
224
|
entity.expose :name
|
225
225
|
|
@@ -238,18 +238,18 @@ describe Grape::Entity do
|
|
238
238
|
get '/example'
|
239
239
|
expect(last_response.status).to eq(200)
|
240
240
|
expect(last_response.headers['Content-type']).to eq('application/xml')
|
241
|
-
expect(last_response.body).to eq
|
242
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
243
|
-
<hash>
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
</hash>
|
248
|
-
XML
|
241
|
+
expect(last_response.body).to eq <<~XML
|
242
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
243
|
+
<hash>
|
244
|
+
<example>
|
245
|
+
<name>johnnyiller</name>
|
246
|
+
</example>
|
247
|
+
</hash>
|
248
|
+
XML
|
249
249
|
end
|
250
250
|
|
251
251
|
it 'presents with json' do
|
252
|
-
entity = Class.new(
|
252
|
+
entity = Class.new(described_class)
|
253
253
|
entity.root 'examples', 'example'
|
254
254
|
entity.expose :name
|
255
255
|
|
@@ -275,7 +275,7 @@ XML
|
|
275
275
|
# Include JSONP middleware
|
276
276
|
subject.use Rack::JSONP
|
277
277
|
|
278
|
-
entity = Class.new(
|
278
|
+
entity = Class.new(described_class)
|
279
279
|
entity.root 'examples', 'example'
|
280
280
|
entity.expose :name
|
281
281
|
|
@@ -315,7 +315,7 @@ XML
|
|
315
315
|
user1 = user.new(name: 'user1')
|
316
316
|
user2 = user.new(name: 'user2')
|
317
317
|
|
318
|
-
entity = Class.new(
|
318
|
+
entity = Class.new(described_class)
|
319
319
|
entity.expose :name
|
320
320
|
|
321
321
|
subject.format :json
|
@@ -326,7 +326,7 @@ XML
|
|
326
326
|
end
|
327
327
|
get '/example'
|
328
328
|
expect_response_json = {
|
329
|
-
'page'
|
329
|
+
'page' => 1,
|
330
330
|
'user1' => { 'name' => 'user1' },
|
331
331
|
'user2' => { 'name' => 'user2' }
|
332
332
|
}
|
@@ -5,6 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe Grape::Exceptions::ValidationErrors do
|
6
6
|
context 'api with rescue_from :all handler' do
|
7
7
|
subject { Class.new(Grape::API) }
|
8
|
+
|
8
9
|
before do
|
9
10
|
subject.rescue_from :all do |_e|
|
10
11
|
rack_response 'message was processed', 400
|
@@ -56,6 +57,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
56
57
|
|
57
58
|
context 'api with rescue_from :grape_exceptions handler' do
|
58
59
|
subject { Class.new(Grape::API) }
|
60
|
+
|
59
61
|
before do
|
60
62
|
subject.rescue_from :all do |_e|
|
61
63
|
rack_response 'message was processed', 400
|
@@ -93,6 +95,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
93
95
|
|
94
96
|
context 'api without a rescue handler' do
|
95
97
|
subject { Class.new(Grape::API) }
|
98
|
+
|
96
99
|
before do
|
97
100
|
subject.params do
|
98
101
|
requires :beer
|