grape 1.5.3 → 1.7.1
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 +92 -0
- data/CONTRIBUTING.md +32 -1
- data/README.md +176 -25
- data/UPGRADING.md +61 -4
- data/grape.gemspec +6 -6
- data/lib/grape/api/instance.rb +14 -18
- data/lib/grape/api.rb +17 -12
- 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 +4 -20
- 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 +13 -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 +22 -37
- data/lib/grape/error_formatter/json.rb +9 -7
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/base.rb +3 -2
- 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 +3 -3
- 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/path.rb +1 -0
- data/lib/grape/request.rb +4 -1
- data/lib/grape/router/attribute_translator.rb +1 -1
- 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/types/invalid_value.rb +8 -0
- data/lib/grape/util/cache.rb +1 -1
- 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 +138 -79
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -0
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
- data/lib/grape/validations/types/invalid_value.rb +0 -7
- 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 +77 -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 +462 -251
- data/spec/grape/config_spec.rb +0 -2
- data/spec/grape/dsl/callbacks_spec.rb +2 -3
- data/spec/grape/dsl/desc_spec.rb +2 -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 +88 -59
- 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 +64 -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 +6 -7
- 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 +28 -19
- 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 +33 -14
- 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/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 +23 -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 +201 -179
- data/spec/grape/validations_spec.rb +171 -79
- 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 +41 -29
- 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/grape/dsl/configuration_spec.rb +0 -16
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -6
- 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
|
78
|
+
expect(last_request.env['api.endpoint']).to be_a(described_class)
|
81
79
|
end
|
82
80
|
|
83
81
|
describe '#status' do
|
@@ -137,20 +135,24 @@ 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(
|
143
142
|
'Host' => 'example.org',
|
144
|
-
'Cookie' => ''
|
143
|
+
'Cookie' => '',
|
144
|
+
'Version' => 'HTTP/1.0'
|
145
145
|
)
|
146
146
|
end
|
147
|
+
|
147
148
|
it 'includes additional request headers' do
|
148
149
|
get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
|
149
150
|
expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
|
150
151
|
end
|
152
|
+
|
151
153
|
it 'includes headers passed as symbols' do
|
152
154
|
env = Rack::MockRequest.env_for('/headers')
|
153
|
-
env[
|
155
|
+
env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
|
154
156
|
body = read_chunks(subject.call(env)[2]).join
|
155
157
|
expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
|
156
158
|
end
|
@@ -212,10 +214,10 @@ describe Grape::Endpoint do
|
|
212
214
|
end
|
213
215
|
get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
|
214
216
|
expect(last_response.body).to eq('3')
|
215
|
-
cookies =
|
217
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").to_h do |set_cookie|
|
216
218
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
217
219
|
[cookie.name, cookie]
|
218
|
-
end
|
220
|
+
end
|
219
221
|
expect(cookies.size).to eq(2)
|
220
222
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
221
223
|
cookie = cookies[cookie_name]
|
@@ -236,10 +238,10 @@ describe Grape::Endpoint do
|
|
236
238
|
end
|
237
239
|
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
|
238
240
|
expect(last_response.body).to eq('3')
|
239
|
-
cookies =
|
241
|
+
cookies = last_response.headers['Set-Cookie'].split("\n").to_h do |set_cookie|
|
240
242
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
241
243
|
[cookie.name, cookie]
|
242
|
-
end
|
244
|
+
end
|
243
245
|
expect(cookies.size).to eq(2)
|
244
246
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
245
247
|
cookie = cookies[cookie_name]
|
@@ -253,7 +255,7 @@ describe Grape::Endpoint do
|
|
253
255
|
|
254
256
|
describe '#params' do
|
255
257
|
context 'default class' do
|
256
|
-
it '
|
258
|
+
it 'is a ActiveSupport::HashWithIndifferentAccess' do
|
257
259
|
subject.get '/foo' do
|
258
260
|
params.class
|
259
261
|
end
|
@@ -339,7 +341,7 @@ describe Grape::Endpoint do
|
|
339
341
|
end
|
340
342
|
|
341
343
|
context 'namespace requirements' do
|
342
|
-
before
|
344
|
+
before do
|
343
345
|
subject.namespace :outer, requirements: { person_email: /abc@(.*).com/ } do
|
344
346
|
get('/:person_email') do
|
345
347
|
params[:person_email]
|
@@ -358,7 +360,7 @@ describe Grape::Endpoint do
|
|
358
360
|
expect(last_response.body).to eq('abc@example.com')
|
359
361
|
end
|
360
362
|
|
361
|
-
it "
|
363
|
+
it "overrides outer namespace's requirements" do
|
362
364
|
get '/outer/inner/someone@testing.wrong/test/1'
|
363
365
|
expect(last_response.status).to eq(404)
|
364
366
|
|
@@ -370,7 +372,7 @@ describe Grape::Endpoint do
|
|
370
372
|
end
|
371
373
|
|
372
374
|
context 'from body parameters' do
|
373
|
-
before
|
375
|
+
before do
|
374
376
|
subject.post '/request_body' do
|
375
377
|
params[:user]
|
376
378
|
end
|
@@ -431,7 +433,28 @@ describe Grape::Endpoint do
|
|
431
433
|
end
|
432
434
|
post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
|
433
435
|
expect(last_response.status).to eq(400)
|
434
|
-
expect(last_response.body).to eq('
|
436
|
+
expect(last_response.body).to eq('file is invalid')
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
context 'when the limit on multipart files is exceeded' do
|
441
|
+
around do |example|
|
442
|
+
limit = Rack::Utils.multipart_part_limit
|
443
|
+
Rack::Utils.multipart_part_limit = 1
|
444
|
+
example.run
|
445
|
+
Rack::Utils.multipart_part_limit = limit
|
446
|
+
end
|
447
|
+
|
448
|
+
it 'returns a 413 if given too many multipart files' do
|
449
|
+
subject.params do
|
450
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
451
|
+
end
|
452
|
+
subject.post '/upload' do
|
453
|
+
params[:file][:filename]
|
454
|
+
end
|
455
|
+
post '/upload', { file: Rack::Test::UploadedFile.new(__FILE__, 'text/plain'), extra: Rack::Test::UploadedFile.new(__FILE__, 'text/plain') }
|
456
|
+
expect(last_response.status).to eq(413)
|
457
|
+
expect(last_response.body).to eq("the number of uploaded files exceeded the system's configured limit (1)")
|
435
458
|
end
|
436
459
|
end
|
437
460
|
|
@@ -469,11 +492,11 @@ describe Grape::Endpoint do
|
|
469
492
|
post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
|
470
493
|
end
|
471
494
|
|
472
|
-
it '
|
495
|
+
it 'does not response with 406 for same type without params' do
|
473
496
|
expect(last_response.status).not_to be 406
|
474
497
|
end
|
475
498
|
|
476
|
-
it '
|
499
|
+
it 'responses with given content type in headers' do
|
477
500
|
expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
|
478
501
|
end
|
479
502
|
end
|
@@ -709,16 +732,18 @@ describe Grape::Endpoint do
|
|
709
732
|
describe '.generate_api_method' do
|
710
733
|
it 'raises NameError if the method name is already in use' do
|
711
734
|
expect do
|
712
|
-
|
735
|
+
described_class.generate_api_method('version', &proc {})
|
713
736
|
end.to raise_error(NameError)
|
714
737
|
end
|
738
|
+
|
715
739
|
it 'raises ArgumentError if a block is not given' do
|
716
740
|
expect do
|
717
|
-
|
741
|
+
described_class.generate_api_method('GET without a block method')
|
718
742
|
end.to raise_error(ArgumentError)
|
719
743
|
end
|
744
|
+
|
720
745
|
it 'returns a Proc' do
|
721
|
-
expect(
|
746
|
+
expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
|
722
747
|
end
|
723
748
|
end
|
724
749
|
|
@@ -777,7 +802,7 @@ describe Grape::Endpoint do
|
|
777
802
|
end
|
778
803
|
|
779
804
|
get '/error_filters'
|
780
|
-
expect(last_response.status).to
|
805
|
+
expect(last_response.status).to be 500
|
781
806
|
expect(called).to match_array %w[before before_validation]
|
782
807
|
end
|
783
808
|
|
@@ -786,8 +811,11 @@ describe Grape::Endpoint do
|
|
786
811
|
subject.before { called << 'parent' }
|
787
812
|
subject.namespace :parent do
|
788
813
|
before { called << 'prior' }
|
814
|
+
|
789
815
|
before { error! :oops, 500 }
|
816
|
+
|
790
817
|
before { called << 'subsequent' }
|
818
|
+
|
791
819
|
get :hello do
|
792
820
|
called << :endpoint
|
793
821
|
'Hello!'
|
@@ -795,7 +823,7 @@ describe Grape::Endpoint do
|
|
795
823
|
end
|
796
824
|
|
797
825
|
get '/parent/hello'
|
798
|
-
expect(last_response.status).to
|
826
|
+
expect(last_response.status).to be 500
|
799
827
|
expect(called).to match_array %w[parent prior]
|
800
828
|
end
|
801
829
|
end
|
@@ -806,19 +834,19 @@ describe Grape::Endpoint do
|
|
806
834
|
it 'allows for the anchoring option with a delete method' do
|
807
835
|
subject.send(:delete, '/example', anchor: true) {}
|
808
836
|
send(:delete, '/example/and/some/more')
|
809
|
-
expect(last_response.status).to
|
837
|
+
expect(last_response.status).to be 404
|
810
838
|
end
|
811
839
|
|
812
840
|
it 'anchors paths by default for the delete method' do
|
813
841
|
subject.send(:delete, '/example') {}
|
814
842
|
send(:delete, '/example/and/some/more')
|
815
|
-
expect(last_response.status).to
|
843
|
+
expect(last_response.status).to be 404
|
816
844
|
end
|
817
845
|
|
818
846
|
it 'responds to /example/and/some/more for the non-anchored delete method' do
|
819
847
|
subject.send(:delete, '/example', anchor: false) {}
|
820
848
|
send(:delete, '/example/and/some/more')
|
821
|
-
expect(last_response.status).to
|
849
|
+
expect(last_response.status).to be 204
|
822
850
|
expect(last_response.body).to be_empty
|
823
851
|
end
|
824
852
|
end
|
@@ -830,7 +858,7 @@ describe Grape::Endpoint do
|
|
830
858
|
body 'deleted'
|
831
859
|
end
|
832
860
|
send(:delete, '/example/and/some/more')
|
833
|
-
expect(last_response.status).to
|
861
|
+
expect(last_response.status).to be 200
|
834
862
|
expect(last_response.body).not_to be_empty
|
835
863
|
end
|
836
864
|
end
|
@@ -839,7 +867,7 @@ describe Grape::Endpoint do
|
|
839
867
|
it 'responds to /example delete method' do
|
840
868
|
subject.delete(:example) { 'deleted' }
|
841
869
|
delete '/example'
|
842
|
-
expect(last_response.status).to
|
870
|
+
expect(last_response.status).to be 200
|
843
871
|
expect(last_response.body).not_to be_empty
|
844
872
|
end
|
845
873
|
end
|
@@ -848,7 +876,7 @@ describe Grape::Endpoint do
|
|
848
876
|
it 'responds to /example delete method' do
|
849
877
|
subject.delete(:example) { nil }
|
850
878
|
delete '/example'
|
851
|
-
expect(last_response.status).to
|
879
|
+
expect(last_response.status).to be 204
|
852
880
|
expect(last_response.body).to be_empty
|
853
881
|
end
|
854
882
|
end
|
@@ -857,7 +885,7 @@ describe Grape::Endpoint do
|
|
857
885
|
it 'responds to /example delete method' do
|
858
886
|
subject.delete(:example) { '' }
|
859
887
|
delete '/example'
|
860
|
-
expect(last_response.status).to
|
888
|
+
expect(last_response.status).to be 204
|
861
889
|
expect(last_response.body).to be_empty
|
862
890
|
end
|
863
891
|
end
|
@@ -869,7 +897,7 @@ describe Grape::Endpoint do
|
|
869
897
|
verb
|
870
898
|
end
|
871
899
|
send(verb, '/example/and/some/more')
|
872
|
-
expect(last_response.status).to
|
900
|
+
expect(last_response.status).to be 404
|
873
901
|
end
|
874
902
|
|
875
903
|
it "anchors paths by default for the #{verb.upcase} method" do
|
@@ -877,7 +905,7 @@ describe Grape::Endpoint do
|
|
877
905
|
verb
|
878
906
|
end
|
879
907
|
send(verb, '/example/and/some/more')
|
880
|
-
expect(last_response.status).to
|
908
|
+
expect(last_response.status).to be 404
|
881
909
|
end
|
882
910
|
|
883
911
|
it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
|
@@ -900,8 +928,9 @@ describe Grape::Endpoint do
|
|
900
928
|
get '/url'
|
901
929
|
expect(last_response.body).to eq('http://example.org/url')
|
902
930
|
end
|
931
|
+
|
903
932
|
['v1', :v1].each do |version|
|
904
|
-
it "
|
933
|
+
it "includes version #{version}" do
|
905
934
|
subject.version version, using: :path
|
906
935
|
subject.get('/url') do
|
907
936
|
request.url
|
@@ -910,7 +939,7 @@ describe Grape::Endpoint do
|
|
910
939
|
expect(last_response.body).to eq("http://example.org/#{version}/url")
|
911
940
|
end
|
912
941
|
end
|
913
|
-
it '
|
942
|
+
it 'includes prefix' do
|
914
943
|
subject.version 'v1', using: :path
|
915
944
|
subject.prefix 'api'
|
916
945
|
subject.get('/url') do
|
@@ -1000,26 +1029,26 @@ describe Grape::Endpoint do
|
|
1000
1029
|
|
1001
1030
|
# In order that the events finalized (time each block ended)
|
1002
1031
|
expect(@events).to contain_exactly(
|
1003
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1032
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1004
1033
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1005
1034
|
type: :before }),
|
1006
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1035
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1007
1036
|
filters: [],
|
1008
1037
|
type: :before_validation }),
|
1009
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1038
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
1010
1039
|
validators: [],
|
1011
1040
|
request: a_kind_of(Grape::Request) }),
|
1012
|
-
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),
|
1013
1042
|
filters: [],
|
1014
1043
|
type: :after_validation }),
|
1015
|
-
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(
|
1016
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1044
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1045
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1017
1046
|
filters: [],
|
1018
1047
|
type: :after }),
|
1019
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1048
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1020
1049
|
filters: [],
|
1021
1050
|
type: :finally }),
|
1022
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1051
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1023
1052
|
env: an_instance_of(Hash) }),
|
1024
1053
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
1025
1054
|
formatter: a_kind_of(Module) })
|
@@ -1027,25 +1056,25 @@ describe Grape::Endpoint do
|
|
1027
1056
|
|
1028
1057
|
# In order that events were initialized
|
1029
1058
|
expect(@events.sort_by(&:time)).to contain_exactly(
|
1030
|
-
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(
|
1059
|
+
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
|
1031
1060
|
env: an_instance_of(Hash) }),
|
1032
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1061
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1033
1062
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1034
1063
|
type: :before }),
|
1035
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1064
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1036
1065
|
filters: [],
|
1037
1066
|
type: :before_validation }),
|
1038
|
-
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(
|
1067
|
+
have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
|
1039
1068
|
validators: [],
|
1040
1069
|
request: a_kind_of(Grape::Request) }),
|
1041
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1070
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1042
1071
|
filters: [],
|
1043
1072
|
type: :after_validation }),
|
1044
|
-
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(
|
1045
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1073
|
+
have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
|
1074
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1046
1075
|
filters: [],
|
1047
1076
|
type: :after }),
|
1048
|
-
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(
|
1077
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
|
1049
1078
|
filters: [],
|
1050
1079
|
type: :finally }),
|
1051
1080
|
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
|