grape 1.3.3 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +111 -2
- data/CONTRIBUTING.md +2 -1
- data/README.md +135 -23
- data/UPGRADING.md +237 -46
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +34 -42
- data/lib/grape/api.rb +21 -16
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +1 -1
- data/lib/grape/dsl/desc.rb +3 -5
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +8 -5
- data/lib/grape/dsl/inside_route.rb +72 -53
- data/lib/grape/dsl/middleware.rb +4 -4
- data/lib/grape/dsl/parameters.rb +11 -7
- data/lib/grape/dsl/request_response.rb +9 -6
- data/lib/grape/dsl/routing.rb +8 -9
- data/lib/grape/dsl/settings.rb +5 -5
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +29 -42
- data/lib/grape/error_formatter/json.rb +2 -6
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/validation.rb +2 -3
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/base.rb +3 -3
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +6 -3
- data/lib/grape/middleware/error.rb +11 -13
- data/lib/grape/middleware/formatter.rb +7 -7
- data/lib/grape/middleware/stack.rb +10 -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/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +4 -1
- data/lib/grape/router/attribute_translator.rb +3 -3
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +31 -30
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +2 -2
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/lazy_value.rb +4 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_iterator.rb +8 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +97 -62
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +4 -5
- data/lib/grape/validations/types.rb +1 -4
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/all_or_none.rb +8 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +6 -8
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
- data/lib/grape/validations/validators/base.rb +74 -69
- data/lib/grape/validations/validators/coerce.rb +63 -76
- data/lib/grape/validations/validators/default.rb +36 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
- data/lib/grape/validations/validators/presence.rb +7 -4
- data/lib/grape/validations/validators/regexp.rb +8 -5
- data/lib/grape/validations/validators/same_as.rb +18 -15
- data/lib/grape/validations/validators/values.rb +61 -56
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +7 -3
- data/spec/grape/api/custom_validations_spec.rb +77 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -3
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +1 -1
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +25 -19
- data/spec/grape/api_spec.rb +576 -211
- data/spec/grape/dsl/callbacks_spec.rb +2 -1
- data/spec/grape/dsl/headers_spec.rb +39 -9
- data/spec/grape/dsl/helpers_spec.rb +3 -2
- data/spec/grape/dsl/inside_route_spec.rb +185 -34
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +2 -1
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +10 -7
- data/spec/grape/endpoint/declared_spec.rb +848 -0
- data/spec/grape/endpoint_spec.rb +77 -589
- data/spec/grape/entity_spec.rb +29 -23
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
- data/spec/grape/exceptions/validation_spec.rb +5 -3
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
- data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
- data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +3 -3
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +28 -7
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +15 -12
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
- data/spec/grape/middleware/versioner/header_spec.rb +14 -13
- data/spec/grape/middleware/versioner/param_spec.rb +7 -1
- data/spec/grape/middleware/versioner/path_spec.rb +5 -1
- data/spec/grape/middleware/versioner_spec.rb +1 -1
- data/spec/grape/parser_spec.rb +4 -0
- data/spec/grape/path_spec.rb +52 -52
- data/spec/grape/presenters/presenter_spec.rb +7 -6
- data/spec/grape/request_spec.rb +6 -4
- data/spec/grape/util/inheritable_setting_spec.rb +7 -7
- data/spec/grape/util/inheritable_values_spec.rb +3 -2
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
- data/spec/grape/util/stackable_values_spec.rb +7 -5
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
- data/spec/grape/validations/params_scope_spec.rb +72 -10
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
- data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
- data/spec/grape/validations/types_spec.rb +8 -8
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
- data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
- data/spec/grape/validations/validators/coerce_spec.rb +248 -33
- data/spec/grape/validations/validators/default_spec.rb +121 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +4 -3
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
- data/spec/grape/validations/validators/presence_spec.rb +16 -1
- data/spec/grape/validations/validators/regexp_spec.rb +25 -31
- data/spec/grape/validations/validators/same_as_spec.rb +14 -20
- data/spec/grape/validations/validators/values_spec.rb +183 -178
- data/spec/grape/validations_spec.rb +342 -29
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +1 -1
- data/spec/integration/multi_xml/xml_spec.rb +1 -1
- data/spec/shared/versioning_examples.rb +32 -29
- data/spec/spec_helper.rb +12 -12
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +4 -6
- metadata +110 -102
data/spec/grape/entity_spec.rb
CHANGED
@@ -32,7 +32,7 @@ describe Grape::Entity do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'pulls a representation from the class options if it exists' do
|
35
|
-
entity = Class.new(
|
35
|
+
entity = Class.new(described_class)
|
36
36
|
allow(entity).to receive(:represent).and_return('Hiya')
|
37
37
|
|
38
38
|
subject.represent Object, with: entity
|
@@ -44,7 +44,7 @@ describe Grape::Entity do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'pulls a representation from the class options if the presented object is a collection of objects' do
|
47
|
-
entity = Class.new(
|
47
|
+
entity = Class.new(described_class)
|
48
48
|
allow(entity).to receive(:represent).and_return('Hiya')
|
49
49
|
|
50
50
|
module EntitySpec
|
@@ -75,7 +75,7 @@ describe Grape::Entity do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'pulls a representation from the class ancestor if it exists' do
|
78
|
-
entity = Class.new(
|
78
|
+
entity = Class.new(described_class)
|
79
79
|
allow(entity).to receive(:represent).and_return('Hiya')
|
80
80
|
|
81
81
|
subclass = Class.new(Object)
|
@@ -90,7 +90,7 @@ describe Grape::Entity do
|
|
90
90
|
|
91
91
|
it 'automatically uses Klass::Entity if that exists' do
|
92
92
|
some_model = Class.new
|
93
|
-
entity = Class.new(
|
93
|
+
entity = Class.new(described_class)
|
94
94
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
95
95
|
|
96
96
|
some_model.const_set :Entity, entity
|
@@ -104,7 +104,7 @@ describe Grape::Entity do
|
|
104
104
|
|
105
105
|
it 'automatically uses Klass::Entity based on the first object in the collection being presented' do
|
106
106
|
some_model = Class.new
|
107
|
-
entity = Class.new(
|
107
|
+
entity = Class.new(described_class)
|
108
108
|
allow(entity).to receive(:represent).and_return('Auto-detect!')
|
109
109
|
|
110
110
|
some_model.const_set :Entity, entity
|
@@ -116,8 +116,8 @@ describe Grape::Entity do
|
|
116
116
|
expect(last_response.body).to eq('Auto-detect!')
|
117
117
|
end
|
118
118
|
|
119
|
-
it 'does not run autodetection for Entity when
|
120
|
-
entity = Class.new(
|
119
|
+
it 'does not run autodetection for Entity when explicitly provided' do
|
120
|
+
entity = Class.new(described_class)
|
121
121
|
some_array = []
|
122
122
|
|
123
123
|
subject.get '/example' do
|
@@ -129,7 +129,7 @@ describe Grape::Entity do
|
|
129
129
|
end
|
130
130
|
|
131
131
|
it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do
|
132
|
-
entity = Class.new(
|
132
|
+
entity = Class.new(described_class)
|
133
133
|
some_relation = Class.new
|
134
134
|
some_model = Class.new
|
135
135
|
|
@@ -173,7 +173,7 @@ describe Grape::Entity do
|
|
173
173
|
|
174
174
|
%i[json serializable_hash].each do |format|
|
175
175
|
it "presents with #{format}" do
|
176
|
-
entity = Class.new(
|
176
|
+
entity = Class.new(described_class)
|
177
177
|
entity.root 'examples', 'example'
|
178
178
|
entity.expose :id
|
179
179
|
|
@@ -181,6 +181,7 @@ describe Grape::Entity do
|
|
181
181
|
subject.get '/example' do
|
182
182
|
c = Class.new do
|
183
183
|
attr_reader :id
|
184
|
+
|
184
185
|
def initialize(id)
|
185
186
|
@id = id
|
186
187
|
end
|
@@ -194,7 +195,7 @@ describe Grape::Entity do
|
|
194
195
|
end
|
195
196
|
|
196
197
|
it "presents with #{format} collection" do
|
197
|
-
entity = Class.new(
|
198
|
+
entity = Class.new(described_class)
|
198
199
|
entity.root 'examples', 'example'
|
199
200
|
entity.expose :id
|
200
201
|
|
@@ -202,6 +203,7 @@ describe Grape::Entity do
|
|
202
203
|
subject.get '/examples' do
|
203
204
|
c = Class.new do
|
204
205
|
attr_reader :id
|
206
|
+
|
205
207
|
def initialize(id)
|
206
208
|
@id = id
|
207
209
|
end
|
@@ -217,7 +219,7 @@ describe Grape::Entity do
|
|
217
219
|
end
|
218
220
|
|
219
221
|
it 'presents with xml' do
|
220
|
-
entity = Class.new(
|
222
|
+
entity = Class.new(described_class)
|
221
223
|
entity.root 'examples', 'example'
|
222
224
|
entity.expose :name
|
223
225
|
|
@@ -226,6 +228,7 @@ describe Grape::Entity do
|
|
226
228
|
subject.get '/example' do
|
227
229
|
c = Class.new do
|
228
230
|
attr_reader :name
|
231
|
+
|
229
232
|
def initialize(args)
|
230
233
|
@name = args[:name] || 'no name set'
|
231
234
|
end
|
@@ -235,18 +238,18 @@ describe Grape::Entity do
|
|
235
238
|
get '/example'
|
236
239
|
expect(last_response.status).to eq(200)
|
237
240
|
expect(last_response.headers['Content-type']).to eq('application/xml')
|
238
|
-
expect(last_response.body).to eq
|
239
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
240
|
-
<hash>
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
</hash>
|
245
|
-
XML
|
241
|
+
expect(last_response.body).to eq <<~XML
|
242
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
243
|
+
<hash>
|
244
|
+
<example>
|
245
|
+
<name>johnnyiller</name>
|
246
|
+
</example>
|
247
|
+
</hash>
|
248
|
+
XML
|
246
249
|
end
|
247
250
|
|
248
251
|
it 'presents with json' do
|
249
|
-
entity = Class.new(
|
252
|
+
entity = Class.new(described_class)
|
250
253
|
entity.root 'examples', 'example'
|
251
254
|
entity.expose :name
|
252
255
|
|
@@ -255,6 +258,7 @@ XML
|
|
255
258
|
subject.get '/example' do
|
256
259
|
c = Class.new do
|
257
260
|
attr_reader :name
|
261
|
+
|
258
262
|
def initialize(args)
|
259
263
|
@name = args[:name] || 'no name set'
|
260
264
|
end
|
@@ -271,7 +275,7 @@ XML
|
|
271
275
|
# Include JSONP middleware
|
272
276
|
subject.use Rack::JSONP
|
273
277
|
|
274
|
-
entity = Class.new(
|
278
|
+
entity = Class.new(described_class)
|
275
279
|
entity.root 'examples', 'example'
|
276
280
|
entity.expose :name
|
277
281
|
|
@@ -284,6 +288,7 @@ XML
|
|
284
288
|
subject.get '/example' do
|
285
289
|
c = Class.new do
|
286
290
|
attr_reader :name
|
291
|
+
|
287
292
|
def initialize(args)
|
288
293
|
@name = args[:name] || 'no name set'
|
289
294
|
end
|
@@ -302,6 +307,7 @@ XML
|
|
302
307
|
it 'present with multiple entities using optional symbol' do
|
303
308
|
user = Class.new do
|
304
309
|
attr_reader :name
|
310
|
+
|
305
311
|
def initialize(args)
|
306
312
|
@name = args[:name] || 'no name set'
|
307
313
|
end
|
@@ -309,7 +315,7 @@ XML
|
|
309
315
|
user1 = user.new(name: 'user1')
|
310
316
|
user2 = user.new(name: 'user2')
|
311
317
|
|
312
|
-
entity = Class.new(
|
318
|
+
entity = Class.new(described_class)
|
313
319
|
entity.expose :name
|
314
320
|
|
315
321
|
subject.format :json
|
@@ -320,7 +326,7 @@ XML
|
|
320
326
|
end
|
321
327
|
get '/example'
|
322
328
|
expect_response_json = {
|
323
|
-
'page'
|
329
|
+
'page' => 1,
|
324
330
|
'user1' => { 'name' => 'user1' },
|
325
331
|
'user2' => { 'name' => 'user2' }
|
326
332
|
}
|
@@ -5,6 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe Grape::Exceptions::ValidationErrors do
|
6
6
|
context 'api with rescue_from :all handler' do
|
7
7
|
subject { Class.new(Grape::API) }
|
8
|
+
|
8
9
|
before do
|
9
10
|
subject.rescue_from :all do |_e|
|
10
11
|
rack_response 'message was processed', 400
|
@@ -56,6 +57,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
56
57
|
|
57
58
|
context 'api with rescue_from :grape_exceptions handler' do
|
58
59
|
subject { Class.new(Grape::API) }
|
60
|
+
|
59
61
|
before do
|
60
62
|
subject.rescue_from :all do |_e|
|
61
63
|
rack_response 'message was processed', 400
|
@@ -93,6 +95,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
93
95
|
|
94
96
|
context 'api without a rescue handler' do
|
95
97
|
subject { Class.new(Grape::API) }
|
98
|
+
|
96
99
|
before do
|
97
100
|
subject.params do
|
98
101
|
requires :beer
|
@@ -7,6 +7,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
7
7
|
it 'does return with status 200' do
|
8
8
|
expect(last_response.status).to eq 200
|
9
9
|
end
|
10
|
+
|
10
11
|
it 'does return the expected result' do
|
11
12
|
expect(last_response.body).to eq('beer received')
|
12
13
|
end
|
@@ -20,6 +21,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
20
21
|
it 'does not include the X-Cascade=pass header' do
|
21
22
|
expect(last_response.headers['X-Cascade']).to be_nil
|
22
23
|
end
|
24
|
+
|
23
25
|
it 'does not accept the request' do
|
24
26
|
expect(last_response.status).to eq 406
|
25
27
|
end
|
@@ -28,6 +30,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
28
30
|
it 'does not include the X-Cascade=pass header' do
|
29
31
|
expect(last_response.headers['X-Cascade']).to be_nil
|
30
32
|
end
|
33
|
+
|
31
34
|
it 'does show rescue handler processing' do
|
32
35
|
expect(last_response.status).to eq 400
|
33
36
|
expect(last_response.body).to eq('message was processed')
|
@@ -36,6 +39,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
36
39
|
|
37
40
|
context 'API with cascade=false and rescue_from :all handler' do
|
38
41
|
subject { Class.new(Grape::API) }
|
42
|
+
|
39
43
|
before do
|
40
44
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
|
41
45
|
subject.rescue_from :all do |e|
|
@@ -52,7 +56,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
52
56
|
|
53
57
|
context 'that received a request with correct vendor and version' do
|
54
58
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
55
|
-
|
59
|
+
|
60
|
+
it_behaves_like 'a valid request'
|
56
61
|
end
|
57
62
|
|
58
63
|
context 'that receives' do
|
@@ -61,13 +66,15 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
61
66
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
|
62
67
|
'CONTENT_TYPE' => 'application/json'
|
63
68
|
end
|
64
|
-
|
69
|
+
|
70
|
+
it_behaves_like 'a rescued request'
|
65
71
|
end
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
69
75
|
context 'API with cascade=false and without a rescue handler' do
|
70
76
|
subject { Class.new(Grape::API) }
|
77
|
+
|
71
78
|
before do
|
72
79
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
|
73
80
|
subject.get '/beer' do
|
@@ -81,23 +88,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
81
88
|
|
82
89
|
context 'that received a request with correct vendor and version' do
|
83
90
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
84
|
-
|
91
|
+
|
92
|
+
it_behaves_like 'a valid request'
|
85
93
|
end
|
86
94
|
|
87
95
|
context 'that receives' do
|
88
96
|
context 'an invalid version in the request' do
|
89
97
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
|
90
|
-
|
98
|
+
|
99
|
+
it_behaves_like 'a not-cascaded request'
|
91
100
|
end
|
101
|
+
|
92
102
|
context 'an invalid vendor in the request' do
|
93
103
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
|
94
|
-
|
104
|
+
|
105
|
+
it_behaves_like 'a not-cascaded request'
|
95
106
|
end
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
99
110
|
context 'API with cascade=false and with rescue_from :all handler and http_codes' do
|
100
111
|
subject { Class.new(Grape::API) }
|
112
|
+
|
101
113
|
before do
|
102
114
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
|
103
115
|
subject.rescue_from :all do |e|
|
@@ -119,7 +131,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
119
131
|
|
120
132
|
context 'that received a request with correct vendor and version' do
|
121
133
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
122
|
-
|
134
|
+
|
135
|
+
it_behaves_like 'a valid request'
|
123
136
|
end
|
124
137
|
|
125
138
|
context 'that receives' do
|
@@ -128,13 +141,15 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
128
141
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
|
129
142
|
'CONTENT_TYPE' => 'application/json'
|
130
143
|
end
|
131
|
-
|
144
|
+
|
145
|
+
it_behaves_like 'a rescued request'
|
132
146
|
end
|
133
147
|
end
|
134
148
|
end
|
135
149
|
|
136
150
|
context 'API with cascade=false, http_codes but without a rescue handler' do
|
137
151
|
subject { Class.new(Grape::API) }
|
152
|
+
|
138
153
|
before do
|
139
154
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
|
140
155
|
subject.desc 'Get beer' do
|
@@ -153,23 +168,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
153
168
|
|
154
169
|
context 'that received a request with correct vendor and version' do
|
155
170
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
156
|
-
|
171
|
+
|
172
|
+
it_behaves_like 'a valid request'
|
157
173
|
end
|
158
174
|
|
159
175
|
context 'that receives' do
|
160
176
|
context 'an invalid version in the request' do
|
161
177
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
|
162
|
-
|
178
|
+
|
179
|
+
it_behaves_like 'a not-cascaded request'
|
163
180
|
end
|
181
|
+
|
164
182
|
context 'an invalid vendor in the request' do
|
165
183
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
|
166
|
-
|
184
|
+
|
185
|
+
it_behaves_like 'a not-cascaded request'
|
167
186
|
end
|
168
187
|
end
|
169
188
|
end
|
170
189
|
|
171
190
|
context 'API with cascade=true and rescue_from :all handler' do
|
172
191
|
subject { Class.new(Grape::API) }
|
192
|
+
|
173
193
|
before do
|
174
194
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
|
175
195
|
subject.rescue_from :all do |e|
|
@@ -186,7 +206,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
186
206
|
|
187
207
|
context 'that received a request with correct vendor and version' do
|
188
208
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
189
|
-
|
209
|
+
|
210
|
+
it_behaves_like 'a valid request'
|
190
211
|
end
|
191
212
|
|
192
213
|
context 'that receives' do
|
@@ -195,20 +216,24 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
195
216
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
|
196
217
|
'CONTENT_TYPE' => 'application/json'
|
197
218
|
end
|
198
|
-
|
219
|
+
|
220
|
+
it_behaves_like 'a cascaded request'
|
199
221
|
end
|
222
|
+
|
200
223
|
context 'an invalid vendor in the request' do
|
201
224
|
before do
|
202
225
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
|
203
226
|
'CONTENT_TYPE' => 'application/json'
|
204
227
|
end
|
205
|
-
|
228
|
+
|
229
|
+
it_behaves_like 'a cascaded request'
|
206
230
|
end
|
207
231
|
end
|
208
232
|
end
|
209
233
|
|
210
234
|
context 'API with cascade=true and without a rescue handler' do
|
211
235
|
subject { Class.new(Grape::API) }
|
236
|
+
|
212
237
|
before do
|
213
238
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
|
214
239
|
subject.get '/beer' do
|
@@ -222,23 +247,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
222
247
|
|
223
248
|
context 'that received a request with correct vendor and version' do
|
224
249
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
225
|
-
|
250
|
+
|
251
|
+
it_behaves_like 'a valid request'
|
226
252
|
end
|
227
253
|
|
228
254
|
context 'that receives' do
|
229
255
|
context 'an invalid version in the request' do
|
230
256
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
|
231
|
-
|
257
|
+
|
258
|
+
it_behaves_like 'a cascaded request'
|
232
259
|
end
|
260
|
+
|
233
261
|
context 'an invalid vendor in the request' do
|
234
262
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
|
235
|
-
|
263
|
+
|
264
|
+
it_behaves_like 'a cascaded request'
|
236
265
|
end
|
237
266
|
end
|
238
267
|
end
|
239
268
|
|
240
269
|
context 'API with cascade=true and with rescue_from :all handler and http_codes' do
|
241
270
|
subject { Class.new(Grape::API) }
|
271
|
+
|
242
272
|
before do
|
243
273
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
|
244
274
|
subject.rescue_from :all do |e|
|
@@ -260,7 +290,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
260
290
|
|
261
291
|
context 'that received a request with correct vendor and version' do
|
262
292
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
263
|
-
|
293
|
+
|
294
|
+
it_behaves_like 'a valid request'
|
264
295
|
end
|
265
296
|
|
266
297
|
context 'that receives' do
|
@@ -269,20 +300,24 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
269
300
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
|
270
301
|
'CONTENT_TYPE' => 'application/json'
|
271
302
|
end
|
272
|
-
|
303
|
+
|
304
|
+
it_behaves_like 'a cascaded request'
|
273
305
|
end
|
306
|
+
|
274
307
|
context 'an invalid vendor in the request' do
|
275
308
|
before do
|
276
309
|
get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
|
277
310
|
'CONTENT_TYPE' => 'application/json'
|
278
311
|
end
|
279
|
-
|
312
|
+
|
313
|
+
it_behaves_like 'a cascaded request'
|
280
314
|
end
|
281
315
|
end
|
282
316
|
end
|
283
317
|
|
284
318
|
context 'API with cascade=true, http_codes but without a rescue handler' do
|
285
319
|
subject { Class.new(Grape::API) }
|
320
|
+
|
286
321
|
before do
|
287
322
|
subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
|
288
323
|
subject.desc 'Get beer' do
|
@@ -301,17 +336,21 @@ describe Grape::Exceptions::InvalidAcceptHeader do
|
|
301
336
|
|
302
337
|
context 'that received a request with correct vendor and version' do
|
303
338
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
|
304
|
-
|
339
|
+
|
340
|
+
it_behaves_like 'a valid request'
|
305
341
|
end
|
306
342
|
|
307
343
|
context 'that receives' do
|
308
344
|
context 'an invalid version in the request' do
|
309
345
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
|
310
|
-
|
346
|
+
|
347
|
+
it_behaves_like 'a cascaded request'
|
311
348
|
end
|
349
|
+
|
312
350
|
context 'an invalid vendor in the request' do
|
313
351
|
before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
|
314
|
-
|
352
|
+
|
353
|
+
it_behaves_like 'a cascaded request'
|
315
354
|
end
|
316
355
|
end
|
317
356
|
end
|
@@ -5,30 +5,31 @@ require 'ostruct'
|
|
5
5
|
|
6
6
|
describe Grape::Exceptions::ValidationErrors do
|
7
7
|
let(:validation_message) { 'FooBar is invalid' }
|
8
|
-
let(:validation_error) {
|
8
|
+
let(:validation_error) { instance_double Grape::Exceptions::Validation, params: [validation_message], message: '' }
|
9
9
|
|
10
10
|
context 'initialize' do
|
11
|
+
subject do
|
12
|
+
described_class.new(errors: [validation_error], headers: headers)
|
13
|
+
end
|
14
|
+
|
11
15
|
let(:headers) do
|
12
16
|
{
|
13
17
|
'A-Header-Key' => 'A-Header-Value'
|
14
18
|
}
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
described_class.new(errors: [validation_error], headers: headers)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should assign headers through base class' do
|
21
|
+
it 'assigns headers through base class' do
|
22
22
|
expect(subject.headers).to eq(headers)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'message' do
|
27
27
|
context 'is not repeated' do
|
28
|
+
subject(:message) { error.message.split(',').map(&:strip) }
|
29
|
+
|
28
30
|
let(:error) do
|
29
31
|
described_class.new(errors: [validation_error, validation_error])
|
30
32
|
end
|
31
|
-
subject(:message) { error.message.split(',').map(&:strip) }
|
32
33
|
|
33
34
|
it { expect(message).to include validation_message }
|
34
35
|
it { expect(message.size).to eq 1 }
|
@@ -37,9 +38,10 @@ describe Grape::Exceptions::ValidationErrors do
|
|
37
38
|
|
38
39
|
describe '#full_messages' do
|
39
40
|
context 'with errors' do
|
41
|
+
subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
|
42
|
+
|
40
43
|
let(:validation_error_1) { Grape::Exceptions::Validation.new(params: ['id'], message: :presence) }
|
41
44
|
let(:validation_error_2) { Grape::Exceptions::Validation.new(params: ['name'], message: :presence) }
|
42
|
-
subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
|
43
45
|
|
44
46
|
it 'returns an array with each errors full message' do
|
45
47
|
expect(subject).to contain_exactly('id is missing', 'name is missing')
|
@@ -47,9 +49,10 @@ describe Grape::Exceptions::ValidationErrors do
|
|
47
49
|
end
|
48
50
|
|
49
51
|
context 'when attributes is an array of symbols' do
|
50
|
-
let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
|
51
52
|
subject { described_class.new(errors: [validation_error]).full_messages }
|
52
53
|
|
54
|
+
let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
|
55
|
+
|
53
56
|
it 'returns an array with an error full message' do
|
54
57
|
expect(subject.first).to eq('admin_field Can not set admin-only field')
|
55
58
|
end
|
@@ -65,7 +68,7 @@ describe Grape::Exceptions::ValidationErrors do
|
|
65
68
|
|
66
69
|
it 'can return structured json with separate fields' do
|
67
70
|
subject.format :json
|
68
|
-
subject.rescue_from
|
71
|
+
subject.rescue_from described_class do |e|
|
69
72
|
error!(e, 400)
|
70
73
|
end
|
71
74
|
subject.params do
|
@@ -4,16 +4,18 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Grape::Exceptions::Validation do
|
6
6
|
it 'fails when params are missing' do
|
7
|
-
expect {
|
7
|
+
expect { described_class.new(message: 'presence') }.to raise_error(ArgumentError, /missing keyword:.+?params/)
|
8
8
|
end
|
9
|
+
|
9
10
|
context 'when message is a symbol' do
|
10
11
|
it 'stores message_key' do
|
11
|
-
expect(
|
12
|
+
expect(described_class.new(params: ['id'], message: :presence).message_key).to eq(:presence)
|
12
13
|
end
|
13
14
|
end
|
15
|
+
|
14
16
|
context 'when message is a String' do
|
15
17
|
it 'does not store the message_key' do
|
16
|
-
expect(
|
18
|
+
expect(described_class.new(params: ['id'], message: 'presence').message_key).to eq(nil)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -10,10 +10,10 @@ describe Grape::Extensions::Hash::ParamBuilder do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'in an endpoint' do
|
13
|
-
|
13
|
+
describe '#params' do
|
14
14
|
before do
|
15
15
|
subject.params do
|
16
|
-
build_with Grape::Extensions::Hash::ParamBuilder
|
16
|
+
build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
|
17
17
|
end
|
18
18
|
|
19
19
|
subject.get do
|
@@ -21,7 +21,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
it '
|
24
|
+
it 'is of type Hash' do
|
25
25
|
get '/'
|
26
26
|
expect(last_response.status).to eq(200)
|
27
27
|
expect(last_response.body).to eq('Hash')
|
@@ -31,17 +31,17 @@ describe Grape::Extensions::Hash::ParamBuilder do
|
|
31
31
|
|
32
32
|
describe 'in an api' do
|
33
33
|
before do
|
34
|
-
subject.send(:include, Grape::Extensions::Hash::ParamBuilder)
|
34
|
+
subject.send(:include, Grape::Extensions::Hash::ParamBuilder) # rubocop:disable RSpec/DescribedClass
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
describe '#params' do
|
38
38
|
before do
|
39
39
|
subject.get do
|
40
40
|
params.class
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
it '
|
44
|
+
it 'is Hash' do
|
45
45
|
get '/'
|
46
46
|
expect(last_response.status).to eq(200)
|
47
47
|
expect(last_response.body).to eq('Hash')
|
@@ -69,7 +69,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
|
|
69
69
|
|
70
70
|
it 'symbolizes the params' do
|
71
71
|
subject.params do
|
72
|
-
build_with Grape::Extensions::Hash::ParamBuilder
|
72
|
+
build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
|
73
73
|
requires :a, type: String
|
74
74
|
end
|
75
75
|
|