grape 1.7.0 → 1.8.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 +46 -0
- data/CONTRIBUTING.md +31 -1
- data/README.md +38 -8
- data/grape.gemspec +2 -2
- data/lib/grape/api.rb +2 -2
- data/lib/grape/content_types.rb +2 -8
- data/lib/grape/dsl/desc.rb +3 -2
- data/lib/grape/dsl/inside_route.rb +6 -6
- data/lib/grape/dsl/parameters.rb +6 -1
- data/lib/grape/dsl/request_response.rb +3 -2
- data/lib/grape/dsl/settings.rb +2 -6
- data/lib/grape/endpoint.rb +21 -19
- data/lib/grape/error_formatter/base.rb +1 -1
- data/lib/grape/exceptions/base.rb +4 -3
- data/lib/grape/exceptions/missing_group_type.rb +1 -6
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
- data/lib/grape/exceptions/validation_errors.rb +1 -6
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
- data/lib/grape/extensions/hash.rb +4 -7
- data/lib/grape/extensions/hashie/mash.rb +3 -3
- data/lib/grape/formatter/serializable_hash.rb +7 -7
- data/lib/grape/middleware/auth/base.rb +1 -1
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/formatter.rb +1 -1
- data/lib/grape/middleware/stack.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +11 -19
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router/attribute_translator.rb +1 -1
- data/lib/grape/router/route.rb +1 -3
- data/lib/grape/types/invalid_value.rb +8 -0
- data/lib/grape/util/cache.rb +1 -1
- data/lib/grape/util/lazy_value.rb +3 -11
- data/lib/grape/util/strict_hash_configuration.rb +3 -4
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +9 -3
- data/lib/grape/validations/single_attribute_iterator.rb +3 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
- data/lib/grape/validations/types/invalid_value.rb +0 -7
- data/lib/grape/validations/validators/base.rb +9 -20
- data/lib/grape/validations/validators/default_validator.rb +2 -20
- data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
- data/lib/grape/validations/validators/values_validator.rb +14 -5
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +19 -3
- data/spec/grape/api/custom_validations_spec.rb +14 -57
- data/spec/grape/api_remount_spec.rb +36 -0
- data/spec/grape/api_spec.rb +15 -21
- data/spec/grape/dsl/desc_spec.rb +84 -85
- data/spec/grape/dsl/inside_route_spec.rb +6 -10
- data/spec/grape/dsl/request_response_spec.rb +21 -2
- data/spec/grape/endpoint_spec.rb +11 -10
- data/spec/grape/exceptions/body_parse_errors_spec.rb +40 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +3 -0
- data/spec/grape/exceptions/missing_group_type_spec.rb +5 -9
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +5 -9
- data/spec/grape/grape_spec.rb +9 -0
- data/spec/grape/integration/rack_spec.rb +6 -5
- data/spec/grape/middleware/base_spec.rb +7 -5
- data/spec/grape/middleware/formatter_spec.rb +7 -7
- data/spec/grape/request_spec.rb +4 -14
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +6 -8
- data/spec/grape/validations/single_attribute_iterator_spec.rb +8 -9
- data/spec/grape/validations/validators/base_spec.rb +38 -0
- data/spec/grape/validations/validators/values_spec.rb +56 -0
- data/spec/grape/validations_spec.rb +36 -12
- data/spec/shared/deprecated_class_examples.rb +16 -0
- metadata +112 -114
- data/lib/grape/config.rb +0 -34
- data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
- data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
- data/spec/grape/config_spec.rb +0 -17
- data/spec/grape/dsl/configuration_spec.rb +0 -14
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -4
@@ -1,48 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
context 'deprecated Grape::Validations::Base' do
|
5
|
-
subject do
|
6
|
-
Class.new(Grape::API) do
|
7
|
-
params do
|
8
|
-
requires :text, validator_with_old_base: true
|
9
|
-
end
|
10
|
-
get do
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:validator_with_old_base) do
|
16
|
-
Class.new(Grape::Validations::Base) do
|
17
|
-
def validate_param!(_attr_name, _params)
|
18
|
-
true
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
before do
|
24
|
-
described_class.register_validator('validator_with_old_base', validator_with_old_base)
|
25
|
-
allow(Warning).to receive(:warn)
|
26
|
-
end
|
3
|
+
require 'shared/deprecated_class_examples'
|
27
4
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def app
|
33
|
-
subject
|
5
|
+
describe Grape::Validations do
|
6
|
+
describe 'Grape::Validations::Base' do
|
7
|
+
let(:deprecated_class) do
|
8
|
+
Class.new(Grape::Validations::Base)
|
34
9
|
end
|
35
10
|
|
36
|
-
|
37
|
-
expect(Warning).to receive(:warn) do |message|
|
38
|
-
expect(message).to include('`Grape::Validations::Base` is deprecated')
|
39
|
-
end
|
40
|
-
|
41
|
-
get '/'
|
42
|
-
end
|
11
|
+
it_behaves_like 'deprecated class'
|
43
12
|
end
|
44
13
|
|
45
|
-
|
14
|
+
describe 'using a custom length validator' do
|
46
15
|
subject do
|
47
16
|
Class.new(Grape::API) do
|
48
17
|
params do
|
@@ -64,6 +33,7 @@ describe Grape::Validations do
|
|
64
33
|
end
|
65
34
|
end
|
66
35
|
end
|
36
|
+
let(:app) { Rack::Builder.new(subject) }
|
67
37
|
|
68
38
|
before do
|
69
39
|
described_class.register_validator('default_length', default_length_validator)
|
@@ -73,10 +43,6 @@ describe Grape::Validations do
|
|
73
43
|
described_class.deregister_validator('default_length')
|
74
44
|
end
|
75
45
|
|
76
|
-
def app
|
77
|
-
subject
|
78
|
-
end
|
79
|
-
|
80
46
|
it 'under 140 characters' do
|
81
47
|
get '/', text: 'abc'
|
82
48
|
expect(last_response.status).to eq 200
|
@@ -96,7 +62,7 @@ describe Grape::Validations do
|
|
96
62
|
end
|
97
63
|
end
|
98
64
|
|
99
|
-
|
65
|
+
describe 'using a custom body-only validator' do
|
100
66
|
subject do
|
101
67
|
Class.new(Grape::API) do
|
102
68
|
params do
|
@@ -115,6 +81,7 @@ describe Grape::Validations do
|
|
115
81
|
end
|
116
82
|
end
|
117
83
|
end
|
84
|
+
let(:app) { Rack::Builder.new(subject) }
|
118
85
|
|
119
86
|
before do
|
120
87
|
described_class.register_validator('in_body', in_body_validator)
|
@@ -124,10 +91,6 @@ describe Grape::Validations do
|
|
124
91
|
described_class.deregister_validator('in_body')
|
125
92
|
end
|
126
93
|
|
127
|
-
def app
|
128
|
-
subject
|
129
|
-
end
|
130
|
-
|
131
94
|
it 'allows field in body' do
|
132
95
|
get '/', text: 'abc'
|
133
96
|
expect(last_response.status).to eq 200
|
@@ -141,7 +104,7 @@ describe Grape::Validations do
|
|
141
104
|
end
|
142
105
|
end
|
143
106
|
|
144
|
-
|
107
|
+
describe 'using a custom validator with message_key' do
|
145
108
|
subject do
|
146
109
|
Class.new(Grape::API) do
|
147
110
|
params do
|
@@ -160,6 +123,7 @@ describe Grape::Validations do
|
|
160
123
|
end
|
161
124
|
end
|
162
125
|
end
|
126
|
+
let(:app) { Rack::Builder.new(subject) }
|
163
127
|
|
164
128
|
before do
|
165
129
|
described_class.register_validator('with_message_key', message_key_validator)
|
@@ -169,10 +133,6 @@ describe Grape::Validations do
|
|
169
133
|
described_class.deregister_validator('with_message_key')
|
170
134
|
end
|
171
135
|
|
172
|
-
def app
|
173
|
-
subject
|
174
|
-
end
|
175
|
-
|
176
136
|
it 'fails with message' do
|
177
137
|
get '/', text: 'foobar'
|
178
138
|
expect(last_response.status).to eq 400
|
@@ -180,7 +140,7 @@ describe Grape::Validations do
|
|
180
140
|
end
|
181
141
|
end
|
182
142
|
|
183
|
-
|
143
|
+
describe 'using a custom request/param validator' do
|
184
144
|
subject do
|
185
145
|
Class.new(Grape::API) do
|
186
146
|
params do
|
@@ -208,6 +168,7 @@ describe Grape::Validations do
|
|
208
168
|
end
|
209
169
|
end
|
210
170
|
end
|
171
|
+
let(:app) { Rack::Builder.new(subject) }
|
211
172
|
|
212
173
|
before do
|
213
174
|
described_class.register_validator('admin', admin_validator)
|
@@ -217,10 +178,6 @@ describe Grape::Validations do
|
|
217
178
|
described_class.deregister_validator('admin')
|
218
179
|
end
|
219
180
|
|
220
|
-
def app
|
221
|
-
subject
|
222
|
-
end
|
223
|
-
|
224
181
|
it 'fail when non-admin user sets an admin field' do
|
225
182
|
get '/', admin_field: 'tester', non_admin_field: 'toaster'
|
226
183
|
expect(last_response.status).to eq 400
|
@@ -147,6 +147,42 @@ describe Grape::API do
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
+
context 'when the params are configured via a configuration' do
|
151
|
+
subject(:a_remounted_api) do
|
152
|
+
Class.new(described_class) do
|
153
|
+
params do
|
154
|
+
requires configuration[:required_attr_name], type: String
|
155
|
+
end
|
156
|
+
|
157
|
+
get(mounted { configuration[:endpoint] }) do
|
158
|
+
status 200
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when the configured param is my_attr' do
|
164
|
+
it 'requires the configured params' do
|
165
|
+
root_api.mount a_remounted_api, with: {
|
166
|
+
required_attr_name: 'my_attr',
|
167
|
+
endpoint: 'test'
|
168
|
+
}
|
169
|
+
get 'test?another_attr=1'
|
170
|
+
expect(last_response.status).to eq 400
|
171
|
+
get 'test?my_attr=1'
|
172
|
+
expect(last_response.status).to eq 200
|
173
|
+
|
174
|
+
root_api.mount a_remounted_api, with: {
|
175
|
+
required_attr_name: 'another_attr',
|
176
|
+
endpoint: 'test_b'
|
177
|
+
}
|
178
|
+
get 'test_b?another_attr=1'
|
179
|
+
expect(last_response.status).to eq 200
|
180
|
+
get 'test_b?my_attr=1'
|
181
|
+
expect(last_response.status).to eq 400
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
150
186
|
context 'when executing a standard block within a `mounted` block with all dynamic params' do
|
151
187
|
subject(:a_remounted_api) do
|
152
188
|
Class.new(described_class) do
|
data/spec/grape/api_spec.rb
CHANGED
@@ -103,22 +103,6 @@ describe Grape::API do
|
|
103
103
|
}
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
107
|
-
# Behavior as defined by rfc2616 when no header is defined
|
108
|
-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
109
|
-
describe 'no specified accept header' do
|
110
|
-
# subject.version 'v1', using: :header
|
111
|
-
# subject.get '/hello' do
|
112
|
-
# 'hello'
|
113
|
-
# end
|
114
|
-
|
115
|
-
# it 'routes' do
|
116
|
-
# get '/hello'
|
117
|
-
# last_response.status.should eql 200
|
118
|
-
# end
|
119
|
-
end
|
120
|
-
|
121
|
-
# pending 'routes if any media type is allowed'
|
122
106
|
end
|
123
107
|
|
124
108
|
describe '.version using accept_version_header' do
|
@@ -448,9 +432,10 @@ describe Grape::API do
|
|
448
432
|
expect(last_response.body).to eql 'hiya'
|
449
433
|
end
|
450
434
|
|
435
|
+
objects = ['string', :symbol, 1, -1.1, {}, [], true, false, nil].freeze
|
451
436
|
%i[put post].each do |verb|
|
452
437
|
context verb.to_s do
|
453
|
-
|
438
|
+
objects.each do |object|
|
454
439
|
it "allows a(n) #{object.class} json object in params" do
|
455
440
|
subject.format :json
|
456
441
|
subject.send(verb) do
|
@@ -1601,7 +1586,7 @@ describe Grape::API do
|
|
1601
1586
|
|
1602
1587
|
subject.get(:hello) { 'Hello, world.' }
|
1603
1588
|
get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
|
1604
|
-
expect(basic_auth_context).to
|
1589
|
+
expect(basic_auth_context).to be_a(Grape::Endpoint)
|
1605
1590
|
end
|
1606
1591
|
|
1607
1592
|
it 'has access to helper methods' do
|
@@ -3067,7 +3052,7 @@ describe Grape::API do
|
|
3067
3052
|
expect(route.description).to eq('first method')
|
3068
3053
|
expect(route.route_foo).to be_nil
|
3069
3054
|
expect(route.params).to eq({})
|
3070
|
-
expect(route.options).to
|
3055
|
+
expect(route.options).to be_a(Hash)
|
3071
3056
|
end
|
3072
3057
|
|
3073
3058
|
it 'has params which does not include format and version as named captures' do
|
@@ -3326,7 +3311,7 @@ describe Grape::API do
|
|
3326
3311
|
it 'is able to cascade' do
|
3327
3312
|
subject.mount lambda { |env|
|
3328
3313
|
headers = {}
|
3329
|
-
headers['X-Cascade'] == 'pass'
|
3314
|
+
headers['X-Cascade'] == 'pass' if env['PATH_INFO'].exclude?('boo')
|
3330
3315
|
[200, headers, ['Farfegnugen']]
|
3331
3316
|
} => '/'
|
3332
3317
|
|
@@ -3725,7 +3710,7 @@ describe Grape::API do
|
|
3725
3710
|
it 'sets the instance' do
|
3726
3711
|
expect(subject.instance).to be_nil
|
3727
3712
|
subject.compile
|
3728
|
-
expect(subject.instance).to
|
3713
|
+
expect(subject.instance).to be_a(subject.base_instance)
|
3729
3714
|
end
|
3730
3715
|
end
|
3731
3716
|
|
@@ -4241,6 +4226,15 @@ describe Grape::API do
|
|
4241
4226
|
end
|
4242
4227
|
end
|
4243
4228
|
|
4229
|
+
it 'does not override methods inherited from Class' do
|
4230
|
+
Class.define_method(:test_method) {}
|
4231
|
+
subclass = Class.new(described_class)
|
4232
|
+
expect(subclass).not_to receive(:add_setup)
|
4233
|
+
subclass.test_method
|
4234
|
+
ensure
|
4235
|
+
Class.remove_method(:test_method)
|
4236
|
+
end
|
4237
|
+
|
4244
4238
|
context 'overriding via composition' do
|
4245
4239
|
module Inherited
|
4246
4240
|
def inherited(api)
|
data/spec/grape/dsl/desc_spec.rb
CHANGED
@@ -1,99 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
describe Grape::DSL::Desc do
|
4
|
+
subject { dummy_class }
|
5
|
+
|
6
|
+
let(:dummy_class) do
|
7
|
+
Class.new do
|
8
|
+
extend Grape::DSL::Desc
|
9
9
|
end
|
10
|
-
|
11
|
-
subject { Class.new(DescSpec::Dummy) }
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
describe '.desc' do
|
13
|
+
it 'sets a description' do
|
14
|
+
desc_text = 'The description'
|
15
|
+
options = { message: 'none' }
|
16
|
+
subject.desc desc_text, options
|
17
|
+
expect(subject.namespace_setting(:description)).to eq(options.merge(description: desc_text))
|
18
|
+
expect(subject.route_setting(:description)).to eq(options.merge(description: desc_text))
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
],
|
42
|
-
hidden: false,
|
43
|
-
deprecated: false,
|
44
|
-
is_array: true,
|
45
|
-
nickname: 'nickname',
|
46
|
-
produces: %w[array of mime_types],
|
47
|
-
consumes: %w[array of mime_types],
|
48
|
-
tags: %w[tag1 tag2],
|
49
|
-
security: %w[array of security schemes]
|
21
|
+
it 'can be set with a block' do
|
22
|
+
expected_options = {
|
23
|
+
summary: 'summary',
|
24
|
+
description: 'The description',
|
25
|
+
detail: 'more details',
|
26
|
+
params: { first: :param },
|
27
|
+
entity: Object,
|
28
|
+
default: { code: 400, message: 'Invalid' },
|
29
|
+
http_codes: [[401, 'Unauthorized', 'Entities::Error']],
|
30
|
+
named: 'My named route',
|
31
|
+
body_name: 'My body name',
|
32
|
+
headers: [
|
33
|
+
XAuthToken: {
|
34
|
+
description: 'Valdates your identity',
|
35
|
+
required: true
|
36
|
+
},
|
37
|
+
XOptionalHeader: {
|
38
|
+
description: 'Not really needed',
|
39
|
+
required: false
|
50
40
|
}
|
41
|
+
],
|
42
|
+
hidden: false,
|
43
|
+
deprecated: false,
|
44
|
+
is_array: true,
|
45
|
+
nickname: 'nickname',
|
46
|
+
produces: %w[array of mime_types],
|
47
|
+
consumes: %w[array of mime_types],
|
48
|
+
tags: %w[tag1 tag2],
|
49
|
+
security: %w[array of security schemes]
|
50
|
+
}
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
52
|
+
subject.desc 'The description' do
|
53
|
+
summary 'summary'
|
54
|
+
detail 'more details'
|
55
|
+
params(first: :param)
|
56
|
+
success Object
|
57
|
+
default code: 400, message: 'Invalid'
|
58
|
+
failure [[401, 'Unauthorized', 'Entities::Error']]
|
59
|
+
named 'My named route'
|
60
|
+
body_name 'My body name'
|
61
|
+
headers [
|
62
|
+
XAuthToken: {
|
63
|
+
description: 'Valdates your identity',
|
64
|
+
required: true
|
65
|
+
},
|
66
|
+
XOptionalHeader: {
|
67
|
+
description: 'Not really needed',
|
68
|
+
required: false
|
69
|
+
}
|
70
|
+
]
|
71
|
+
hidden false
|
72
|
+
deprecated false
|
73
|
+
is_array true
|
74
|
+
nickname 'nickname'
|
75
|
+
produces %w[array of mime_types]
|
76
|
+
consumes %w[array of mime_types]
|
77
|
+
tags %w[tag1 tag2]
|
78
|
+
security %w[array of security schemes]
|
79
|
+
end
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
expect(subject.namespace_setting(:description)).to eq(expected_options)
|
82
|
+
expect(subject.route_setting(:description)).to eq(expected_options)
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
85
|
+
it 'can be set with options and a block' do
|
86
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with('Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.')
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
93
|
-
expect(subject.namespace_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
94
|
-
expect(subject.route_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
95
|
-
end
|
88
|
+
desc_text = 'The description'
|
89
|
+
detail_text = 'more details'
|
90
|
+
options = { message: 'none' }
|
91
|
+
subject.desc desc_text, options do
|
92
|
+
detail detail_text
|
96
93
|
end
|
94
|
+
expect(subject.namespace_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
95
|
+
expect(subject.route_setting(:description)).to eq(description: desc_text, detail: detail_text)
|
97
96
|
end
|
98
97
|
end
|
99
98
|
end
|
@@ -203,16 +203,12 @@ describe Grape::Endpoint do
|
|
203
203
|
end
|
204
204
|
|
205
205
|
describe '#file' do
|
206
|
-
before do
|
207
|
-
allow(subject).to receive(:warn)
|
208
|
-
end
|
209
|
-
|
210
206
|
describe 'set' do
|
211
207
|
context 'as file path' do
|
212
208
|
let(:file_path) { '/some/file/path' }
|
213
209
|
|
214
210
|
it 'emits a warning that this method is deprecated' do
|
215
|
-
expect(
|
211
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with(/Use sendfile or stream/)
|
216
212
|
|
217
213
|
subject.file file_path
|
218
214
|
end
|
@@ -228,7 +224,7 @@ describe Grape::Endpoint do
|
|
228
224
|
let(:file_object) { double('StreamerObject', each: nil) }
|
229
225
|
|
230
226
|
it 'emits a warning that this method is deprecated' do
|
231
|
-
expect(
|
227
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with(/Use stream to use a Stream object/)
|
232
228
|
|
233
229
|
subject.file file_object
|
234
230
|
end
|
@@ -243,7 +239,7 @@ describe Grape::Endpoint do
|
|
243
239
|
|
244
240
|
describe 'get' do
|
245
241
|
it 'emits a warning that this method is deprecated' do
|
246
|
-
expect(
|
242
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with(/Use sendfile or stream/)
|
247
243
|
|
248
244
|
subject.file
|
249
245
|
end
|
@@ -273,7 +269,7 @@ describe Grape::Endpoint do
|
|
273
269
|
end
|
274
270
|
|
275
271
|
it 'sends no deprecation warnings' do
|
276
|
-
expect(
|
272
|
+
expect(ActiveSupport::Deprecation).not_to receive(:warn)
|
277
273
|
|
278
274
|
subject.sendfile file_path
|
279
275
|
end
|
@@ -334,7 +330,7 @@ describe Grape::Endpoint do
|
|
334
330
|
end
|
335
331
|
|
336
332
|
it 'emits no deprecation warnings' do
|
337
|
-
expect(
|
333
|
+
expect(ActiveSupport::Deprecation).not_to receive(:warn)
|
338
334
|
|
339
335
|
subject.stream file_path
|
340
336
|
end
|
@@ -384,7 +380,7 @@ describe Grape::Endpoint do
|
|
384
380
|
end
|
385
381
|
|
386
382
|
it 'emits no deprecation warnings' do
|
387
|
-
expect(
|
383
|
+
expect(ActiveSupport::Deprecation).not_to receive(:warn)
|
388
384
|
|
389
385
|
subject.stream stream_object
|
390
386
|
end
|
@@ -148,13 +148,32 @@ module Grape
|
|
148
148
|
it 'sets rescue all to true' do
|
149
149
|
expect(subject).to receive(:namespace_inheritable).with(:rescue_all, true)
|
150
150
|
expect(subject).to receive(:namespace_inheritable).with(:rescue_grape_exceptions, true)
|
151
|
+
expect(subject).to receive(:namespace_inheritable).with(:grape_exceptions_rescue_handler, nil)
|
151
152
|
subject.rescue_from :grape_exceptions
|
152
153
|
end
|
153
154
|
|
154
|
-
it 'sets
|
155
|
+
it 'sets given proc as rescue handler' do
|
156
|
+
rescue_handler_proc = proc {}
|
155
157
|
expect(subject).to receive(:namespace_inheritable).with(:rescue_all, true)
|
156
158
|
expect(subject).to receive(:namespace_inheritable).with(:rescue_grape_exceptions, true)
|
157
|
-
subject.
|
159
|
+
expect(subject).to receive(:namespace_inheritable).with(:grape_exceptions_rescue_handler, rescue_handler_proc)
|
160
|
+
subject.rescue_from :grape_exceptions, rescue_handler_proc
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'sets given block as rescue handler' do
|
164
|
+
rescue_handler_proc = proc {}
|
165
|
+
expect(subject).to receive(:namespace_inheritable).with(:rescue_all, true)
|
166
|
+
expect(subject).to receive(:namespace_inheritable).with(:rescue_grape_exceptions, true)
|
167
|
+
expect(subject).to receive(:namespace_inheritable).with(:grape_exceptions_rescue_handler, rescue_handler_proc)
|
168
|
+
subject.rescue_from :grape_exceptions, &rescue_handler_proc
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'sets a rescue handler declared through :with option' do
|
172
|
+
with_block = -> { 'hello' }
|
173
|
+
expect(subject).to receive(:namespace_inheritable).with(:rescue_all, true)
|
174
|
+
expect(subject).to receive(:namespace_inheritable).with(:rescue_grape_exceptions, true)
|
175
|
+
expect(subject).to receive(:namespace_inheritable).with(:grape_exceptions_rescue_handler, an_instance_of(Proc))
|
176
|
+
subject.rescue_from :grape_exceptions, with: with_block
|
158
177
|
end
|
159
178
|
end
|
160
179
|
|
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -75,7 +75,7 @@ describe Grape::Endpoint do
|
|
75
75
|
it 'sets itself in the env upon call' do
|
76
76
|
subject.get('/') { 'Hello world.' }
|
77
77
|
get '/'
|
78
|
-
expect(last_request.env['api.endpoint']).to
|
78
|
+
expect(last_request.env['api.endpoint']).to be_a(described_class)
|
79
79
|
end
|
80
80
|
|
81
81
|
describe '#status' do
|
@@ -138,7 +138,7 @@ describe Grape::Endpoint do
|
|
138
138
|
|
139
139
|
it 'includes request headers' do
|
140
140
|
get '/headers'
|
141
|
-
expect(JSON.parse(last_response.body)).to
|
141
|
+
expect(JSON.parse(last_response.body)).to include(
|
142
142
|
'Host' => 'example.org',
|
143
143
|
'Cookie' => ''
|
144
144
|
)
|
@@ -173,7 +173,7 @@ describe Grape::Endpoint do
|
|
173
173
|
|
174
174
|
get('/get/cookies')
|
175
175
|
|
176
|
-
expect(last_response.headers['Set-Cookie'].split("\n").sort).to eql [
|
176
|
+
expect(Array(last_response.headers['Set-Cookie']).flat_map { |h| h.split("\n") }.sort).to eql [
|
177
177
|
'cookie3=symbol',
|
178
178
|
'cookie4=secret+code+here',
|
179
179
|
'my-awesome-cookie1=is+cool',
|
@@ -198,8 +198,9 @@ describe Grape::Endpoint do
|
|
198
198
|
end
|
199
199
|
get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
|
200
200
|
expect(last_response.body).to eq('user_test')
|
201
|
-
|
202
|
-
expect(
|
201
|
+
cookies = Array(last_response.headers['Set-Cookie']).flat_map { |h| h.split("\n") }
|
202
|
+
expect(cookies.first).to match(/username=user_test/)
|
203
|
+
expect(cookies.second).to match(/sandbox=true/)
|
203
204
|
end
|
204
205
|
|
205
206
|
it 'deletes cookie' do
|
@@ -213,10 +214,10 @@ describe Grape::Endpoint do
|
|
213
214
|
end
|
214
215
|
get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
|
215
216
|
expect(last_response.body).to eq('3')
|
216
|
-
cookies = last_response.headers['Set-Cookie'].split("\n").
|
217
|
+
cookies = Array(last_response.headers['Set-Cookie']).flat_map { |h| h.split("\n") }.to_h do |set_cookie|
|
217
218
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
218
219
|
[cookie.name, cookie]
|
219
|
-
end
|
220
|
+
end
|
220
221
|
expect(cookies.size).to eq(2)
|
221
222
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
222
223
|
cookie = cookies[cookie_name]
|
@@ -237,10 +238,10 @@ describe Grape::Endpoint do
|
|
237
238
|
end
|
238
239
|
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
|
239
240
|
expect(last_response.body).to eq('3')
|
240
|
-
cookies = last_response.headers['Set-Cookie'].split("\n").
|
241
|
+
cookies = Array(last_response.headers['Set-Cookie']).flat_map { |h| h.split("\n") }.to_h do |set_cookie|
|
241
242
|
cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
|
242
243
|
[cookie.name, cookie]
|
243
|
-
end
|
244
|
+
end
|
244
245
|
expect(cookies.size).to eq(2)
|
245
246
|
%w[and_this delete_this_cookie].each do |cookie_name|
|
246
247
|
cookie = cookies[cookie_name]
|
@@ -432,7 +433,7 @@ describe Grape::Endpoint do
|
|
432
433
|
end
|
433
434
|
post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
|
434
435
|
expect(last_response.status).to eq(400)
|
435
|
-
expect(last_response.body).to eq('
|
436
|
+
expect(last_response.body).to eq('file is invalid')
|
436
437
|
end
|
437
438
|
end
|
438
439
|
|