grape 1.5.3 → 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 +67 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +150 -21
- data/UPGRADING.md +61 -4
- data/grape.gemspec +5 -5
- 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 +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 +20 -35
- 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/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/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/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 -0
- 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 +69 -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 +457 -231
- 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 +86 -58
- 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 +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 +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 +126 -117
- 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
|
@@ -431,7 +432,28 @@ describe Grape::Endpoint do
|
|
431
432
|
end
|
432
433
|
post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
|
433
434
|
expect(last_response.status).to eq(400)
|
434
|
-
expect(last_response.body).to eq('
|
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)")
|
435
457
|
end
|
436
458
|
end
|
437
459
|
|
@@ -469,11 +491,11 @@ describe Grape::Endpoint do
|
|
469
491
|
post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
|
470
492
|
end
|
471
493
|
|
472
|
-
it '
|
494
|
+
it 'does not response with 406 for same type without params' do
|
473
495
|
expect(last_response.status).not_to be 406
|
474
496
|
end
|
475
497
|
|
476
|
-
it '
|
498
|
+
it 'responses with given content type in headers' do
|
477
499
|
expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
|
478
500
|
end
|
479
501
|
end
|
@@ -709,16 +731,18 @@ describe Grape::Endpoint do
|
|
709
731
|
describe '.generate_api_method' do
|
710
732
|
it 'raises NameError if the method name is already in use' do
|
711
733
|
expect do
|
712
|
-
|
734
|
+
described_class.generate_api_method('version', &proc {})
|
713
735
|
end.to raise_error(NameError)
|
714
736
|
end
|
737
|
+
|
715
738
|
it 'raises ArgumentError if a block is not given' do
|
716
739
|
expect do
|
717
|
-
|
740
|
+
described_class.generate_api_method('GET without a block method')
|
718
741
|
end.to raise_error(ArgumentError)
|
719
742
|
end
|
743
|
+
|
720
744
|
it 'returns a Proc' do
|
721
|
-
expect(
|
745
|
+
expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
|
722
746
|
end
|
723
747
|
end
|
724
748
|
|
@@ -777,7 +801,7 @@ describe Grape::Endpoint do
|
|
777
801
|
end
|
778
802
|
|
779
803
|
get '/error_filters'
|
780
|
-
expect(last_response.status).to
|
804
|
+
expect(last_response.status).to be 500
|
781
805
|
expect(called).to match_array %w[before before_validation]
|
782
806
|
end
|
783
807
|
|
@@ -786,8 +810,11 @@ describe Grape::Endpoint do
|
|
786
810
|
subject.before { called << 'parent' }
|
787
811
|
subject.namespace :parent do
|
788
812
|
before { called << 'prior' }
|
813
|
+
|
789
814
|
before { error! :oops, 500 }
|
815
|
+
|
790
816
|
before { called << 'subsequent' }
|
817
|
+
|
791
818
|
get :hello do
|
792
819
|
called << :endpoint
|
793
820
|
'Hello!'
|
@@ -795,7 +822,7 @@ describe Grape::Endpoint do
|
|
795
822
|
end
|
796
823
|
|
797
824
|
get '/parent/hello'
|
798
|
-
expect(last_response.status).to
|
825
|
+
expect(last_response.status).to be 500
|
799
826
|
expect(called).to match_array %w[parent prior]
|
800
827
|
end
|
801
828
|
end
|
@@ -806,19 +833,19 @@ describe Grape::Endpoint do
|
|
806
833
|
it 'allows for the anchoring option with a delete method' do
|
807
834
|
subject.send(:delete, '/example', anchor: true) {}
|
808
835
|
send(:delete, '/example/and/some/more')
|
809
|
-
expect(last_response.status).to
|
836
|
+
expect(last_response.status).to be 404
|
810
837
|
end
|
811
838
|
|
812
839
|
it 'anchors paths by default for the delete method' do
|
813
840
|
subject.send(:delete, '/example') {}
|
814
841
|
send(:delete, '/example/and/some/more')
|
815
|
-
expect(last_response.status).to
|
842
|
+
expect(last_response.status).to be 404
|
816
843
|
end
|
817
844
|
|
818
845
|
it 'responds to /example/and/some/more for the non-anchored delete method' do
|
819
846
|
subject.send(:delete, '/example', anchor: false) {}
|
820
847
|
send(:delete, '/example/and/some/more')
|
821
|
-
expect(last_response.status).to
|
848
|
+
expect(last_response.status).to be 204
|
822
849
|
expect(last_response.body).to be_empty
|
823
850
|
end
|
824
851
|
end
|
@@ -830,7 +857,7 @@ describe Grape::Endpoint do
|
|
830
857
|
body 'deleted'
|
831
858
|
end
|
832
859
|
send(:delete, '/example/and/some/more')
|
833
|
-
expect(last_response.status).to
|
860
|
+
expect(last_response.status).to be 200
|
834
861
|
expect(last_response.body).not_to be_empty
|
835
862
|
end
|
836
863
|
end
|
@@ -839,7 +866,7 @@ describe Grape::Endpoint do
|
|
839
866
|
it 'responds to /example delete method' do
|
840
867
|
subject.delete(:example) { 'deleted' }
|
841
868
|
delete '/example'
|
842
|
-
expect(last_response.status).to
|
869
|
+
expect(last_response.status).to be 200
|
843
870
|
expect(last_response.body).not_to be_empty
|
844
871
|
end
|
845
872
|
end
|
@@ -848,7 +875,7 @@ describe Grape::Endpoint do
|
|
848
875
|
it 'responds to /example delete method' do
|
849
876
|
subject.delete(:example) { nil }
|
850
877
|
delete '/example'
|
851
|
-
expect(last_response.status).to
|
878
|
+
expect(last_response.status).to be 204
|
852
879
|
expect(last_response.body).to be_empty
|
853
880
|
end
|
854
881
|
end
|
@@ -857,7 +884,7 @@ describe Grape::Endpoint do
|
|
857
884
|
it 'responds to /example delete method' do
|
858
885
|
subject.delete(:example) { '' }
|
859
886
|
delete '/example'
|
860
|
-
expect(last_response.status).to
|
887
|
+
expect(last_response.status).to be 204
|
861
888
|
expect(last_response.body).to be_empty
|
862
889
|
end
|
863
890
|
end
|
@@ -869,7 +896,7 @@ describe Grape::Endpoint do
|
|
869
896
|
verb
|
870
897
|
end
|
871
898
|
send(verb, '/example/and/some/more')
|
872
|
-
expect(last_response.status).to
|
899
|
+
expect(last_response.status).to be 404
|
873
900
|
end
|
874
901
|
|
875
902
|
it "anchors paths by default for the #{verb.upcase} method" do
|
@@ -877,7 +904,7 @@ describe Grape::Endpoint do
|
|
877
904
|
verb
|
878
905
|
end
|
879
906
|
send(verb, '/example/and/some/more')
|
880
|
-
expect(last_response.status).to
|
907
|
+
expect(last_response.status).to be 404
|
881
908
|
end
|
882
909
|
|
883
910
|
it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
|
@@ -900,8 +927,9 @@ describe Grape::Endpoint do
|
|
900
927
|
get '/url'
|
901
928
|
expect(last_response.body).to eq('http://example.org/url')
|
902
929
|
end
|
930
|
+
|
903
931
|
['v1', :v1].each do |version|
|
904
|
-
it "
|
932
|
+
it "includes version #{version}" do
|
905
933
|
subject.version version, using: :path
|
906
934
|
subject.get('/url') do
|
907
935
|
request.url
|
@@ -910,7 +938,7 @@ describe Grape::Endpoint do
|
|
910
938
|
expect(last_response.body).to eq("http://example.org/#{version}/url")
|
911
939
|
end
|
912
940
|
end
|
913
|
-
it '
|
941
|
+
it 'includes prefix' do
|
914
942
|
subject.version 'v1', using: :path
|
915
943
|
subject.prefix 'api'
|
916
944
|
subject.get('/url') do
|
@@ -1000,26 +1028,26 @@ describe Grape::Endpoint do
|
|
1000
1028
|
|
1001
1029
|
# In order that the events finalized (time each block ended)
|
1002
1030
|
expect(@events).to contain_exactly(
|
1003
|
-
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),
|
1004
1032
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1005
1033
|
type: :before }),
|
1006
|
-
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),
|
1007
1035
|
filters: [],
|
1008
1036
|
type: :before_validation }),
|
1009
|
-
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),
|
1010
1038
|
validators: [],
|
1011
1039
|
request: a_kind_of(Grape::Request) }),
|
1012
|
-
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),
|
1013
1041
|
filters: [],
|
1014
1042
|
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(
|
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),
|
1017
1045
|
filters: [],
|
1018
1046
|
type: :after }),
|
1019
|
-
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),
|
1020
1048
|
filters: [],
|
1021
1049
|
type: :finally }),
|
1022
|
-
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),
|
1023
1051
|
env: an_instance_of(Hash) }),
|
1024
1052
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
1025
1053
|
formatter: a_kind_of(Module) })
|
@@ -1027,25 +1055,25 @@ describe Grape::Endpoint do
|
|
1027
1055
|
|
1028
1056
|
# In order that events were initialized
|
1029
1057
|
expect(@events.sort_by(&:time)).to contain_exactly(
|
1030
|
-
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),
|
1031
1059
|
env: an_instance_of(Hash) }),
|
1032
|
-
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),
|
1033
1061
|
filters: a_collection_containing_exactly(an_instance_of(Proc)),
|
1034
1062
|
type: :before }),
|
1035
|
-
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),
|
1036
1064
|
filters: [],
|
1037
1065
|
type: :before_validation }),
|
1038
|
-
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),
|
1039
1067
|
validators: [],
|
1040
1068
|
request: a_kind_of(Grape::Request) }),
|
1041
|
-
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),
|
1042
1070
|
filters: [],
|
1043
1071
|
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(
|
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),
|
1046
1074
|
filters: [],
|
1047
1075
|
type: :after }),
|
1048
|
-
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),
|
1049
1077
|
filters: [],
|
1050
1078
|
type: :finally }),
|
1051
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
|