grape 1.5.2 → 1.7.0
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 +75 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +152 -21
- data/UPGRADING.md +86 -2
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +14 -18
- data/lib/grape/api.rb +18 -13
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dry_types.rb +12 -0
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/callbacks.rb +0 -2
- data/lib/grape/dsl/configuration.rb +0 -2
- data/lib/grape/dsl/desc.rb +2 -19
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +7 -7
- data/lib/grape/dsl/inside_route.rb +43 -30
- data/lib/grape/dsl/middleware.rb +4 -6
- data/lib/grape/dsl/parameters.rb +8 -10
- data/lib/grape/dsl/request_response.rb +9 -8
- data/lib/grape/dsl/routing.rb +6 -4
- data/lib/grape/dsl/settings.rb +5 -7
- data/lib/grape/dsl/validations.rb +0 -15
- data/lib/grape/endpoint.rb +21 -36
- data/lib/grape/error_formatter/json.rb +9 -7
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/missing_group_type.rb +8 -1
- data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
- data/lib/grape/exceptions/validation.rb +1 -6
- 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 +9 -8
- data/lib/grape/middleware/auth/dsl.rb +7 -2
- data/lib/grape/middleware/base.rb +3 -1
- data/lib/grape/middleware/error.rb +2 -2
- 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 +5 -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/json.rb +2 -0
- data/lib/grape/util/lazy_value.rb +3 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_doc.rb +58 -0
- data/lib/grape/validations/params_scope.rb +137 -78
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +16 -8
- data/lib/grape/validations/types/set_coercer.rb +0 -2
- data/lib/grape/validations/types.rb +98 -30
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +82 -70
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/default_validator.rb +51 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +88 -0
- data/lib/grape/validations.rb +16 -6
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +70 -29
- data/spec/grape/api/custom_validations_spec.rb +116 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -5
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
- data/spec/grape/api/documentation_spec.rb +59 -0
- data/spec/grape/api/inherited_helpers_spec.rb +0 -2
- data/spec/grape/api/instance_spec.rb +0 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -2
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/nested_helpers_spec.rb +0 -2
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/parameters_modification_spec.rb +0 -2
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
- data/spec/grape/api/recognize_path_spec.rb +1 -3
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
- data/spec/grape/api/shared_helpers_spec.rb +0 -2
- data/spec/grape/api_remount_spec.rb +16 -16
- data/spec/grape/api_spec.rb +527 -224
- data/spec/grape/config_spec.rb +0 -2
- data/spec/grape/dsl/callbacks_spec.rb +2 -3
- data/spec/grape/dsl/configuration_spec.rb +0 -2
- data/spec/grape/dsl/desc_spec.rb +0 -2
- data/spec/grape/dsl/headers_spec.rb +39 -11
- data/spec/grape/dsl/helpers_spec.rb +3 -4
- data/spec/grape/dsl/inside_route_spec.rb +16 -16
- data/spec/grape/dsl/logger_spec.rb +15 -19
- data/spec/grape/dsl/middleware_spec.rb +2 -3
- data/spec/grape/dsl/parameters_spec.rb +2 -2
- data/spec/grape/dsl/request_response_spec.rb +7 -8
- data/spec/grape/dsl/routing_spec.rb +11 -10
- data/spec/grape/dsl/settings_spec.rb +0 -2
- data/spec/grape/dsl/validations_spec.rb +0 -17
- data/spec/grape/endpoint/declared_spec.rb +261 -16
- data/spec/grape/endpoint_spec.rb +98 -57
- data/spec/grape/entity_spec.rb +22 -23
- data/spec/grape/exceptions/base_spec.rb +16 -2
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
- data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
- data/spec/grape/exceptions/missing_option_spec.rb +1 -3
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
- data/spec/grape/exceptions/validation_spec.rb +5 -5
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
- data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
- data/spec/grape/integration/rack_spec.rb +0 -2
- data/spec/grape/loading_spec.rb +8 -10
- data/spec/grape/middleware/auth/base_spec.rb +0 -1
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
- data/spec/grape/middleware/base_spec.rb +24 -17
- data/spec/grape/middleware/error_spec.rb +8 -3
- data/spec/grape/middleware/exception_spec.rb +111 -163
- data/spec/grape/middleware/formatter_spec.rb +27 -8
- data/spec/grape/middleware/globals_spec.rb +7 -6
- data/spec/grape/middleware/stack_spec.rb +14 -14
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
- data/spec/grape/middleware/versioner/header_spec.rb +30 -15
- data/spec/grape/middleware/versioner/param_spec.rb +7 -3
- data/spec/grape/middleware/versioner/path_spec.rb +5 -3
- data/spec/grape/middleware/versioner_spec.rb +1 -3
- data/spec/grape/named_api_spec.rb +0 -2
- data/spec/grape/parser_spec.rb +4 -2
- data/spec/grape/path_spec.rb +52 -54
- data/spec/grape/presenters/presenter_spec.rb +7 -8
- data/spec/grape/request_spec.rb +6 -6
- data/spec/grape/util/inheritable_setting_spec.rb +7 -8
- data/spec/grape/util/inheritable_values_spec.rb +3 -3
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
- data/spec/grape/util/stackable_values_spec.rb +7 -6
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
- data/spec/grape/validations/attributes_doc_spec.rb +153 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
- data/spec/grape/validations/params_scope_spec.rb +361 -96
- data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
- data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
- data/spec/grape/validations/types_spec.rb +36 -10
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
- data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
- data/spec/grape/validations/validators/coerce_spec.rb +99 -24
- data/spec/grape/validations/validators/default_spec.rb +72 -80
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
- data/spec/grape/validations/validators/except_values_spec.rb +3 -5
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
- data/spec/grape/validations/validators/presence_spec.rb +16 -3
- data/spec/grape/validations/validators/regexp_spec.rb +25 -33
- data/spec/grape/validations/validators/same_as_spec.rb +14 -22
- data/spec/grape/validations/validators/values_spec.rb +182 -179
- data/spec/grape/validations_spec.rb +149 -80
- data/spec/integration/eager_load/eager_load_spec.rb +2 -2
- data/spec/integration/multi_json/json_spec.rb +1 -3
- data/spec/integration/multi_xml/xml_spec.rb +1 -3
- data/spec/shared/versioning_examples.rb +12 -9
- data/spec/spec_helper.rb +21 -6
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- metadata +125 -115
- data/lib/grape/validations/validators/all_or_none.rb +0 -15
- data/lib/grape/validations/validators/allow_blank.rb +0 -18
- data/lib/grape/validations/validators/as.rb +0 -16
- data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
- data/lib/grape/validations/validators/coerce.rb +0 -91
- data/lib/grape/validations/validators/default.rb +0 -48
- data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
- data/lib/grape/validations/validators/except_values.rb +0 -22
- data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
- data/lib/grape/validations/validators/presence.rb +0 -12
- data/lib/grape/validations/validators/regexp.rb +0 -13
- data/lib/grape/validations/validators/same_as.rb +0 -26
- data/lib/grape/validations/validators/values.rb +0 -83
- data/spec/support/eager_load.rb +0 -19
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Endpoint do
|
6
4
|
subject { Class.new(Grape::API) }
|
7
5
|
|
@@ -10,32 +8,32 @@ describe Grape::Endpoint do
|
|
10
8
|
end
|
11
9
|
|
12
10
|
describe '.before_each' do
|
13
|
-
after {
|
11
|
+
after { described_class.before_each.clear }
|
14
12
|
|
15
13
|
it 'is settable via block' do
|
16
14
|
block = ->(_endpoint) { 'noop' }
|
17
|
-
|
18
|
-
expect(
|
15
|
+
described_class.before_each(&block)
|
16
|
+
expect(described_class.before_each.first).to eq(block)
|
19
17
|
end
|
20
18
|
|
21
19
|
it 'is settable via reference' do
|
22
20
|
block = ->(_endpoint) { 'noop' }
|
23
|
-
|
24
|
-
expect(
|
21
|
+
described_class.before_each block
|
22
|
+
expect(described_class.before_each.first).to eq(block)
|
25
23
|
end
|
26
24
|
|
27
25
|
it 'is able to override a helper' do
|
28
26
|
subject.get('/') { current_user }
|
29
27
|
expect { get '/' }.to raise_error(NameError)
|
30
28
|
|
31
|
-
|
29
|
+
described_class.before_each do |endpoint|
|
32
30
|
allow(endpoint).to receive(:current_user).and_return('Bob')
|
33
31
|
end
|
34
32
|
|
35
33
|
get '/'
|
36
34
|
expect(last_response.body).to eq('Bob')
|
37
35
|
|
38
|
-
|
36
|
+
described_class.before_each(nil)
|
39
37
|
expect { get '/' }.to raise_error(NameError)
|
40
38
|
end
|
41
39
|
|
@@ -46,18 +44,18 @@ describe Grape::Endpoint do
|
|
46
44
|
end
|
47
45
|
expect { get '/' }.to raise_error(NameError)
|
48
46
|
|
49
|
-
|
47
|
+
described_class.before_each do |endpoint|
|
50
48
|
allow(endpoint).to receive(:current_user).and_return('Bob')
|
51
49
|
end
|
52
50
|
|
53
|
-
|
51
|
+
described_class.before_each do |endpoint|
|
54
52
|
allow(endpoint).to receive(:authenticate_user!).and_return(true)
|
55
53
|
end
|
56
54
|
|
57
55
|
get '/'
|
58
56
|
expect(last_response.body).to eq('Bob')
|
59
57
|
|
60
|
-
|
58
|
+
described_class.before_each(nil)
|
61
59
|
expect { get '/' }.to raise_error(NameError)
|
62
60
|
end
|
63
61
|
end
|
@@ -66,7 +64,7 @@ describe Grape::Endpoint do
|
|
66
64
|
it 'takes a settings stack, options, and a block' do
|
67
65
|
p = proc {}
|
68
66
|
expect do
|
69
|
-
|
67
|
+
described_class.new(Grape::Util::InheritableSetting.new, {
|
70
68
|
path: '/',
|
71
69
|
method: :get
|
72
70
|
}, &p)
|
@@ -77,7 +75,7 @@ describe Grape::Endpoint do
|
|
77
75
|
it 'sets itself in the env upon call' do
|
78
76
|
subject.get('/') { 'Hello world.' }
|
79
77
|
get '/'
|
80
|
-
expect(last_request.env['api.endpoint']).to be_kind_of(
|
78
|
+
expect(last_request.env['api.endpoint']).to be_kind_of(described_class)
|
81
79
|
end
|
82
80
|
|
83
81
|
describe '#status' do
|
@@ -137,6 +135,7 @@ describe Grape::Endpoint do
|
|
137
135
|
headers.to_json
|
138
136
|
end
|
139
137
|
end
|
138
|
+
|
140
139
|
it 'includes request headers' do
|
141
140
|
get '/headers'
|
142
141
|
expect(JSON.parse(last_response.body)).to eq(
|
@@ -144,13 +143,15 @@ describe Grape::Endpoint do
|
|
144
143
|
'Cookie' => ''
|
145
144
|
)
|
146
145
|
end
|
146
|
+
|
147
147
|
it 'includes additional request headers' do
|
148
148
|
get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
|
149
149
|
expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
|
150
150
|
end
|
151
|
+
|
151
152
|
it 'includes headers passed as symbols' do
|
152
153
|
env = Rack::MockRequest.env_for('/headers')
|
153
|
-
env[
|
154
|
+
env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
|
154
155
|
body = read_chunks(subject.call(env)[2]).join
|
155
156
|
expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
|
156
157
|
end
|
@@ -212,10 +213,10 @@ describe Grape::Endpoint do
|
|
212
213
|
end
|
213
214
|
get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
|
214
215
|
expect(last_response.body).to eq('3')
|
215
|
-
cookies =
|
216
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
|
216
217
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
217
218
|
[cookie.name, cookie]
|
218
|
-
end
|
219
|
+
end.to_h
|
219
220
|
expect(cookies.size).to eq(2)
|
220
221
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
221
222
|
cookie = cookies[cookie_name]
|
@@ -236,10 +237,10 @@ describe Grape::Endpoint do
|
|
236
237
|
end
|
237
238
|
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
|
238
239
|
expect(last_response.body).to eq('3')
|
239
|
-
cookies =
|
240
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
|
240
241
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
241
242
|
[cookie.name, cookie]
|
242
|
-
end
|
243
|
+
end.to_h
|
243
244
|
expect(cookies.size).to eq(2)
|
244
245
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
245
246
|
cookie = cookies[cookie_name]
|
@@ -253,7 +254,7 @@ describe Grape::Endpoint do
|
|
253
254
|
|
254
255
|
describe '#params' do
|
255
256
|
context 'default class' do
|
256
|
-
it '
|
257
|
+
it 'is a ActiveSupport::HashWithIndifferentAccess' do
|
257
258
|
subject.get '/foo' do
|
258
259
|
params.class
|
259
260
|
end
|
@@ -339,7 +340,7 @@ describe Grape::Endpoint do
|
|
339
340
|
end
|
340
341
|
|
341
342
|
context 'namespace requirements' do
|
342
|
-
before
|
343
|
+
before do
|
343
344
|
subject.namespace :outer, requirements: { person_email: /abc@(.*).com/ } do
|
344
345
|
get('/:person_email') do
|
345
346
|
params[:person_email]
|
@@ -358,7 +359,7 @@ describe Grape::Endpoint do
|
|
358
359
|
expect(last_response.body).to eq('abc@example.com')
|
359
360
|
end
|
360
361
|
|
361
|
-
it "
|
362
|
+
it "overrides outer namespace's requirements" do
|
362
363
|
get '/outer/inner/someone@testing.wrong/test/1'
|
363
364
|
expect(last_response.status).to eq(404)
|
364
365
|
|
@@ -370,7 +371,7 @@ describe Grape::Endpoint do
|
|
370
371
|
end
|
371
372
|
|
372
373
|
context 'from body parameters' do
|
373
|
-
before
|
374
|
+
before do
|
374
375
|
subject.post '/request_body' do
|
375
376
|
params[:user]
|
376
377
|
end
|
@@ -420,6 +421,40 @@ describe Grape::Endpoint do
|
|
420
421
|
expect(last_response.status).to eq(201)
|
421
422
|
expect(last_response.body).to eq('Bob')
|
422
423
|
end
|
424
|
+
|
425
|
+
# Rack swallowed this error until v2.2.0
|
426
|
+
it 'returns a 400 if given an invalid multipart body', if: Gem::Version.new(Rack.release) >= Gem::Version.new('2.2.0') do
|
427
|
+
subject.params do
|
428
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
429
|
+
end
|
430
|
+
subject.post '/upload' do
|
431
|
+
params[:file][:filename]
|
432
|
+
end
|
433
|
+
post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
|
434
|
+
expect(last_response.status).to eq(400)
|
435
|
+
expect(last_response.body).to eq('empty message body supplied with multipart/form-data; boundary=foobar content-type')
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'when the limit on multipart files is exceeded' do
|
440
|
+
around do |example|
|
441
|
+
limit = Rack::Utils.multipart_part_limit
|
442
|
+
Rack::Utils.multipart_part_limit = 1
|
443
|
+
example.run
|
444
|
+
Rack::Utils.multipart_part_limit = limit
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'returns a 413 if given too many multipart files' do
|
448
|
+
subject.params do
|
449
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
450
|
+
end
|
451
|
+
subject.post '/upload' do
|
452
|
+
params[:file][:filename]
|
453
|
+
end
|
454
|
+
post '/upload', { file: Rack::Test::UploadedFile.new(__FILE__, 'text/plain'), extra: Rack::Test::UploadedFile.new(__FILE__, 'text/plain') }
|
455
|
+
expect(last_response.status).to eq(413)
|
456
|
+
expect(last_response.body).to eq("the number of uploaded files exceeded the system's configured limit (1)")
|
457
|
+
end
|
423
458
|
end
|
424
459
|
|
425
460
|
it 'responds with a 415 for an unsupported content-type' do
|
@@ -456,11 +491,11 @@ describe Grape::Endpoint do
|
|
456
491
|
post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
|
457
492
|
end
|
458
493
|
|
459
|
-
it '
|
494
|
+
it 'does not response with 406 for same type without params' do
|
460
495
|
expect(last_response.status).not_to be 406
|
461
496
|
end
|
462
497
|
|
463
|
-
it '
|
498
|
+
it 'responses with given content type in headers' do
|
464
499
|
expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
|
465
500
|
end
|
466
501
|
end
|
@@ -696,16 +731,18 @@ describe Grape::Endpoint do
|
|
696
731
|
describe '.generate_api_method' do
|
697
732
|
it 'raises NameError if the method name is already in use' do
|
698
733
|
expect do
|
699
|
-
|
734
|
+
described_class.generate_api_method('version', &proc {})
|
700
735
|
end.to raise_error(NameError)
|
701
736
|
end
|
737
|
+
|
702
738
|
it 'raises ArgumentError if a block is not given' do
|
703
739
|
expect do
|
704
|
-
|
740
|
+
described_class.generate_api_method('GET without a block method')
|
705
741
|
end.to raise_error(ArgumentError)
|
706
742
|
end
|
743
|
+
|
707
744
|
it 'returns a Proc' do
|
708
|
-
expect(
|
745
|
+
expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
|
709
746
|
end
|
710
747
|
end
|
711
748
|
|
@@ -764,7 +801,7 @@ describe Grape::Endpoint do
|
|
764
801
|
end
|
765
802
|
|
766
803
|
get '/error_filters'
|
767
|
-
expect(last_response.status).to
|
804
|
+
expect(last_response.status).to be 500
|
768
805
|
expect(called).to match_array %w[before before_validation]
|
769
806
|
end
|
770
807
|
|
@@ -773,8 +810,11 @@ describe Grape::Endpoint do
|
|
773
810
|
subject.before { called << 'parent' }
|
774
811
|
subject.namespace :parent do
|
775
812
|
before { called << 'prior' }
|
813
|
+
|
776
814
|
before { error! :oops, 500 }
|
815
|
+
|
777
816
|
before { called << 'subsequent' }
|
817
|
+
|
778
818
|
get :hello do
|
779
819
|
called << :endpoint
|
780
820
|
'Hello!'
|
@@ -782,7 +822,7 @@ describe Grape::Endpoint do
|
|
782
822
|
end
|
783
823
|
|
784
824
|
get '/parent/hello'
|
785
|
-
expect(last_response.status).to
|
825
|
+
expect(last_response.status).to be 500
|
786
826
|
expect(called).to match_array %w[parent prior]
|
787
827
|
end
|
788
828
|
end
|
@@ -793,19 +833,19 @@ describe Grape::Endpoint do
|
|
793
833
|
it 'allows for the anchoring option with a delete method' do
|
794
834
|
subject.send(:delete, '/example', anchor: true) {}
|
795
835
|
send(:delete, '/example/and/some/more')
|
796
|
-
expect(last_response.status).to
|
836
|
+
expect(last_response.status).to be 404
|
797
837
|
end
|
798
838
|
|
799
839
|
it 'anchors paths by default for the delete method' do
|
800
840
|
subject.send(:delete, '/example') {}
|
801
841
|
send(:delete, '/example/and/some/more')
|
802
|
-
expect(last_response.status).to
|
842
|
+
expect(last_response.status).to be 404
|
803
843
|
end
|
804
844
|
|
805
845
|
it 'responds to /example/and/some/more for the non-anchored delete method' do
|
806
846
|
subject.send(:delete, '/example', anchor: false) {}
|
807
847
|
send(:delete, '/example/and/some/more')
|
808
|
-
expect(last_response.status).to
|
848
|
+
expect(last_response.status).to be 204
|
809
849
|
expect(last_response.body).to be_empty
|
810
850
|
end
|
811
851
|
end
|
@@ -817,7 +857,7 @@ describe Grape::Endpoint do
|
|
817
857
|
body 'deleted'
|
818
858
|
end
|
819
859
|
send(:delete, '/example/and/some/more')
|
820
|
-
expect(last_response.status).to
|
860
|
+
expect(last_response.status).to be 200
|
821
861
|
expect(last_response.body).not_to be_empty
|
822
862
|
end
|
823
863
|
end
|
@@ -826,7 +866,7 @@ describe Grape::Endpoint do
|
|
826
866
|
it 'responds to /example delete method' do
|
827
867
|
subject.delete(:example) { 'deleted' }
|
828
868
|
delete '/example'
|
829
|
-
expect(last_response.status).to
|
869
|
+
expect(last_response.status).to be 200
|
830
870
|
expect(last_response.body).not_to be_empty
|
831
871
|
end
|
832
872
|
end
|
@@ -835,7 +875,7 @@ describe Grape::Endpoint do
|
|
835
875
|
it 'responds to /example delete method' do
|
836
876
|
subject.delete(:example) { nil }
|
837
877
|
delete '/example'
|
838
|
-
expect(last_response.status).to
|
878
|
+
expect(last_response.status).to be 204
|
839
879
|
expect(last_response.body).to be_empty
|
840
880
|
end
|
841
881
|
end
|
@@ -844,7 +884,7 @@ describe Grape::Endpoint do
|
|
844
884
|
it 'responds to /example delete method' do
|
845
885
|
subject.delete(:example) { '' }
|
846
886
|
delete '/example'
|
847
|
-
expect(last_response.status).to
|
887
|
+
expect(last_response.status).to be 204
|
848
888
|
expect(last_response.body).to be_empty
|
849
889
|
end
|
850
890
|
end
|
@@ -856,7 +896,7 @@ describe Grape::Endpoint do
|
|
856
896
|
verb
|
857
897
|
end
|
858
898
|
send(verb, '/example/and/some/more')
|
859
|
-
expect(last_response.status).to
|
899
|
+
expect(last_response.status).to be 404
|
860
900
|
end
|
861
901
|
|
862
902
|
it "anchors paths by default for the #{verb.upcase} method" do
|
@@ -864,7 +904,7 @@ describe Grape::Endpoint do
|
|
864
904
|
verb
|
865
905
|
end
|
866
906
|
send(verb, '/example/and/some/more')
|
867
|
-
expect(last_response.status).to
|
907
|
+
expect(last_response.status).to be 404
|
868
908
|
end
|
869
909
|
|
870
910
|
it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
|
@@ -887,8 +927,9 @@ describe Grape::Endpoint do
|
|
887
927
|
get '/url'
|
888
928
|
expect(last_response.body).to eq('http://example.org/url')
|
889
929
|
end
|
930
|
+
|
890
931
|
['v1', :v1].each do |version|
|
891
|
-
it "
|
932
|
+
it "includes version #{version}" do
|
892
933
|
subject.version version, using: :path
|
893
934
|
subject.get('/url') do
|
894
935
|
request.url
|
@@ -897,7 +938,7 @@ describe Grape::Endpoint do
|
|
897
938
|
expect(last_response.body).to eq("http://example.org/#{version}/url")
|
898
939
|
end
|
899
940
|
end
|
900
|
-
it '
|
941
|
+
it 'includes prefix' do
|
901
942
|
subject.version 'v1', using: :path
|
902
943
|
subject.prefix 'api'
|
903
944
|
subject.get('/url') do
|
@@ -987,26 +1028,26 @@ describe Grape::Endpoint do
|
|
987
1028
|
|
988
1029
|
# In order that the events finalized (time each block ended)
|
989
1030
|
expect(@events).to contain_exactly(
|
990
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1031
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
991
1032
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
992
1033
|
type: :before }),
|
993
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1034
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
994
1035
|
filters: [],
|
995
1036
|
type: :before_validation }),
|
996
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1037
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
997
1038
|
validators: [],
|
998
1039
|
request: a_kind_of(Grape::Request) }),
|
999
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1040
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1000
1041
|
filters: [],
|
1001
1042
|
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(
|
1043
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1044
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1004
1045
|
filters: [],
|
1005
1046
|
type: :after }),
|
1006
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1047
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1007
1048
|
filters: [],
|
1008
1049
|
type: :finally }),
|
1009
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1050
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1010
1051
|
env: an_instance_of(Hash) }),
|
1011
1052
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
1012
1053
|
formatter: a_kind_of(Module) })
|
@@ -1014,25 +1055,25 @@ describe Grape::Endpoint do
|
|
1014
1055
|
|
1015
1056
|
# In order that events were initialized
|
1016
1057
|
expect(@events.sort_by(&:time)).to contain_exactly(
|
1017
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1058
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1018
1059
|
env: an_instance_of(Hash) }),
|
1019
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1060
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1020
1061
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1021
1062
|
type: :before }),
|
1022
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1063
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1023
1064
|
filters: [],
|
1024
1065
|
type: :before_validation }),
|
1025
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1066
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
1026
1067
|
validators: [],
|
1027
1068
|
request: a_kind_of(Grape::Request) }),
|
1028
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1069
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1029
1070
|
filters: [],
|
1030
1071
|
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(
|
1072
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1073
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1033
1074
|
filters: [],
|
1034
1075
|
type: :after }),
|
1035
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1076
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1036
1077
|
filters: [],
|
1037
1078
|
type: :finally }),
|
1038
1079
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
data/spec/grape/entity_spec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
3
|
require 'grape_entity'
|
5
4
|
|
6
5
|
describe Grape::Entity do
|
@@ -32,7 +31,7 @@ describe Grape::Entity do
|
|
32
31
|
end
|
33
32
|
|
34
33
|
it 'pulls a representation from the class options if it exists' do
|
35
|
-
entity = Class.new(
|
34
|
+
entity = Class.new(described_class)
|
36
35
|
allow(entity).to receive(:represent).and_return('Hiya')
|
37
36
|
|
38
37
|
subject.represent Object, with: entity
|
@@ -44,7 +43,7 @@ describe Grape::Entity do
|
|
44
43
|
end
|
45
44
|
|
46
45
|
it 'pulls a representation from the class options if the presented object is a collection of objects' do
|
47
|
-
entity = Class.new(
|
46
|
+
entity = Class.new(described_class)
|
48
47
|
allow(entity).to receive(:represent).and_return('Hiya')
|
49
48
|
|
50
49
|
module EntitySpec
|
@@ -75,7 +74,7 @@ describe Grape::Entity do
|
|
75
74
|
end
|
76
75
|
|
77
76
|
it 'pulls a representation from the class ancestor if it exists' do
|
78
|
-
entity = Class.new(
|
77
|
+
entity = Class.new(described_class)
|
79
78
|
allow(entity).to receive(:represent).and_return('Hiya')
|
80
79
|
|
81
80
|
subclass = Class.new(Object)
|
@@ -90,7 +89,7 @@ describe Grape::Entity do
|
|
90
89
|
|
91
90
|
it 'automatically uses Klass::Entity if that exists' do
|
92
91
|
some_model = Class.new
|
93
|
-
entity = Class.new(
|
92
|
+
entity = Class.new(described_class)
|
94
93
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
95
94
|
|
96
95
|
some_model.const_set :Entity, entity
|
@@ -104,7 +103,7 @@ describe Grape::Entity do
|
|
104
103
|
|
105
104
|
it 'automatically uses Klass::Entity based on the first object in the collection being presented' do
|
106
105
|
some_model = Class.new
|
107
|
-
entity = Class.new(
|
106
|
+
entity = Class.new(described_class)
|
108
107
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
109
108
|
|
110
109
|
some_model.const_set :Entity, entity
|
@@ -117,7 +116,7 @@ describe Grape::Entity do
|
|
117
116
|
end
|
118
117
|
|
119
118
|
it 'does not run autodetection for Entity when explicitly provided' do
|
120
|
-
entity = Class.new(
|
119
|
+
entity = Class.new(described_class)
|
121
120
|
some_array = []
|
122
121
|
|
123
122
|
subject.get '/example' do
|
@@ -129,7 +128,7 @@ describe Grape::Entity do
|
|
129
128
|
end
|
130
129
|
|
131
130
|
it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do
|
132
|
-
entity = Class.new(
|
131
|
+
entity = Class.new(described_class)
|
133
132
|
some_relation = Class.new
|
134
133
|
some_model = Class.new
|
135
134
|
|
@@ -173,7 +172,7 @@ describe Grape::Entity do
|
|
173
172
|
|
174
173
|
%i[json serializable_hash].each do |format|
|
175
174
|
it "presents with #{format}" do
|
176
|
-
entity = Class.new(
|
175
|
+
entity = Class.new(described_class)
|
177
176
|
entity.root 'examples', 'example'
|
178
177
|
entity.expose :id
|
179
178
|
|
@@ -195,7 +194,7 @@ describe Grape::Entity do
|
|
195
194
|
end
|
196
195
|
|
197
196
|
it "presents with #{format} collection" do
|
198
|
-
entity = Class.new(
|
197
|
+
entity = Class.new(described_class)
|
199
198
|
entity.root 'examples', 'example'
|
200
199
|
entity.expose :id
|
201
200
|
|
@@ -219,7 +218,7 @@ describe Grape::Entity do
|
|
219
218
|
end
|
220
219
|
|
221
220
|
it 'presents with xml' do
|
222
|
-
entity = Class.new(
|
221
|
+
entity = Class.new(described_class)
|
223
222
|
entity.root 'examples', 'example'
|
224
223
|
entity.expose :name
|
225
224
|
|
@@ -238,18 +237,18 @@ describe Grape::Entity do
|
|
238
237
|
get '/example'
|
239
238
|
expect(last_response.status).to eq(200)
|
240
239
|
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
|
240
|
+
expect(last_response.body).to eq <<~XML
|
241
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
242
|
+
<hash>
|
243
|
+
<example>
|
244
|
+
<name>johnnyiller</name>
|
245
|
+
</example>
|
246
|
+
</hash>
|
247
|
+
XML
|
249
248
|
end
|
250
249
|
|
251
250
|
it 'presents with json' do
|
252
|
-
entity = Class.new(
|
251
|
+
entity = Class.new(described_class)
|
253
252
|
entity.root 'examples', 'example'
|
254
253
|
entity.expose :name
|
255
254
|
|
@@ -275,7 +274,7 @@ XML
|
|
275
274
|
# Include JSONP middleware
|
276
275
|
subject.use Rack::JSONP
|
277
276
|
|
278
|
-
entity = Class.new(
|
277
|
+
entity = Class.new(described_class)
|
279
278
|
entity.root 'examples', 'example'
|
280
279
|
entity.expose :name
|
281
280
|
|
@@ -315,7 +314,7 @@ XML
|
|
315
314
|
user1 = user.new(name: 'user1')
|
316
315
|
user2 = user.new(name: 'user2')
|
317
316
|
|
318
|
-
entity = Class.new(
|
317
|
+
entity = Class.new(described_class)
|
319
318
|
entity.expose :name
|
320
319
|
|
321
320
|
subject.format :json
|
@@ -326,7 +325,7 @@ XML
|
|
326
325
|
end
|
327
326
|
get '/example'
|
328
327
|
expect_response_json = {
|
329
|
-
'page'
|
328
|
+
'page' => 1,
|
330
329
|
'user1' => { 'name' => 'user1' },
|
331
330
|
'user2' => { 'name' => 'user2' }
|
332
331
|
}
|
@@ -1,8 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Exceptions::Base do
|
4
|
+
describe '#to_s' do
|
5
|
+
subject { described_class.new(message: message).to_s }
|
6
|
+
|
7
|
+
let(:message) { 'a_message' }
|
8
|
+
|
9
|
+
it { is_expected.to eq(message) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#message' do
|
13
|
+
subject { described_class.new(message: message).message }
|
14
|
+
|
15
|
+
let(:message) { 'a_message' }
|
16
|
+
|
17
|
+
it { is_expected.to eq(message) }
|
18
|
+
end
|
19
|
+
|
6
20
|
describe '#compose_message' do
|
7
21
|
subject { described_class.new.send(:compose_message, key, **attributes) }
|
8
22
|
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Exceptions::ValidationErrors do
|
6
4
|
context 'api with rescue_from :all handler' do
|
7
5
|
subject { Class.new(Grape::API) }
|
6
|
+
|
8
7
|
before do
|
9
8
|
subject.rescue_from :all do |_e|
|
10
9
|
rack_response 'message was processed', 400
|
@@ -56,6 +55,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
56
55
|
|
57
56
|
context 'api with rescue_from :grape_exceptions handler' do
|
58
57
|
subject { Class.new(Grape::API) }
|
58
|
+
|
59
59
|
before do
|
60
60
|
subject.rescue_from :all do |_e|
|
61
61
|
rack_response 'message was processed', 400
|
@@ -93,6 +93,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
93
93
|
|
94
94
|
context 'api without a rescue handler' do
|
95
95
|
subject { Class.new(Grape::API) }
|
96
|
+
|
96
97
|
before do
|
97
98
|
subject.params do
|
98
99
|
requires :beer
|