grape 2.2.0 → 2.3.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 +26 -0
- data/README.md +7 -6
- data/UPGRADING.md +19 -0
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +22 -58
- data/lib/grape/api.rb +2 -11
- data/lib/grape/dsl/desc.rb +27 -24
- data/lib/grape/dsl/inside_route.rb +12 -23
- data/lib/grape/dsl/parameters.rb +2 -2
- data/lib/grape/dsl/routing.rb +5 -12
- data/lib/grape/endpoint.rb +76 -79
- data/lib/grape/error_formatter/base.rb +51 -21
- data/lib/grape/error_formatter/json.rb +7 -24
- data/lib/grape/error_formatter/jsonapi.rb +7 -0
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +13 -20
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +4 -12
- data/lib/grape/exceptions/base.rb +18 -30
- data/lib/grape/exceptions/validation.rb +5 -4
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +4 -6
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +4 -12
- data/lib/grape/http/headers.rb +1 -0
- data/lib/grape/middleware/error.rb +2 -0
- data/lib/grape/middleware/formatter.rb +1 -1
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -3
- data/lib/grape/middleware/versioner/base.rb +82 -0
- data/lib/grape/middleware/versioner/header.rb +3 -9
- data/lib/grape/middleware/versioner/param.rb +0 -2
- data/lib/grape/middleware/versioner/path.rb +0 -2
- data/lib/grape/middleware/versioner.rb +5 -3
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/jsonapi.rb +7 -0
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -7
- data/lib/grape/path.rb +39 -56
- data/lib/grape/request.rb +2 -2
- data/lib/grape/router/base_route.rb +2 -2
- data/lib/grape/router/greedy_route.rb +2 -2
- data/lib/grape/router/pattern.rb +23 -18
- data/lib/grape/router/route.rb +13 -5
- data/lib/grape/router.rb +5 -5
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/validations/contract_scope.rb +2 -39
- data/lib/grape/validations/params_scope.rb +7 -11
- data/lib/grape/validations/types/dry_type_coercer.rb +10 -6
- data/lib/grape/validations/validator_factory.rb +2 -2
- data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
- data/lib/grape/validations/validators/base.rb +5 -9
- data/lib/grape/validations/validators/coerce_validator.rb +1 -1
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +1 -1
- data/lib/grape/validations/validators/except_values_validator.rb +1 -1
- data/lib/grape/validations/validators/length_validator.rb +1 -1
- data/lib/grape/validations/validators/regexp_validator.rb +1 -1
- data/lib/grape/validations/validators/values_validator.rb +15 -57
- data/lib/grape/validations.rb +8 -17
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +1 -1
- metadata +14 -11
- data/lib/grape/middleware/versioner_helpers.rb +0 -75
- data/lib/grape/validations/types/build_coercer.rb +0 -92
data/lib/grape/endpoint.rb
CHANGED
@@ -145,27 +145,28 @@ module Grape
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def mount_in(router)
|
148
|
-
if endpoints
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end
|
148
|
+
return endpoints.each { |e| e.mount_in(router) } if endpoints
|
149
|
+
|
150
|
+
reset_routes!
|
151
|
+
routes.each do |route|
|
152
|
+
router.append(route.apply(self))
|
153
|
+
next unless !namespace_inheritable(:do_not_route_head) && route.request_method == Rack::GET
|
154
|
+
|
155
|
+
route.dup.then do |head_route|
|
156
|
+
head_route.convert_to_head_request!
|
157
|
+
router.append(head_route.apply(self))
|
159
158
|
end
|
160
159
|
end
|
161
160
|
end
|
162
161
|
|
163
162
|
def to_routes
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
163
|
+
default_route_options = prepare_default_route_attributes
|
164
|
+
default_path_settings = prepare_default_path_settings
|
165
|
+
|
166
|
+
map_routes do |method, raw_path|
|
167
|
+
prepared_path = Path.new(raw_path, namespace, default_path_settings)
|
168
|
+
params = options[:route_options].present? ? options[:route_options].merge(default_route_options) : default_route_options
|
169
|
+
route = Grape::Router::Route.new(method, prepared_path.origin, prepared_path.suffix, params)
|
169
170
|
route.apply(self)
|
170
171
|
end.flatten
|
171
172
|
end
|
@@ -196,19 +197,14 @@ module Grape
|
|
196
197
|
version.length == 1 ? version.first : version
|
197
198
|
end
|
198
199
|
|
199
|
-
def merge_route_options(**default)
|
200
|
-
options[:route_options].clone.merge!(**default)
|
201
|
-
end
|
202
|
-
|
203
200
|
def map_routes
|
204
201
|
options[:method].map { |method| options[:path].map { |path| yield method, path } }
|
205
202
|
end
|
206
203
|
|
207
|
-
def
|
204
|
+
def prepare_default_path_settings
|
208
205
|
namespace_stackable_hash = inheritable_setting.namespace_stackable.to_hash
|
209
206
|
namespace_inheritable_hash = inheritable_setting.namespace_inheritable.to_hash
|
210
|
-
|
211
|
-
Path.new(path, namespace, path_settings)
|
207
|
+
namespace_stackable_hash.merge!(namespace_inheritable_hash)
|
212
208
|
end
|
213
209
|
|
214
210
|
def namespace
|
@@ -259,9 +255,10 @@ module Grape
|
|
259
255
|
run_filters befores, :before
|
260
256
|
|
261
257
|
if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
|
262
|
-
|
258
|
+
allow_header_value = allowed_methods.join(', ')
|
259
|
+
raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allow_header_value)) unless options?
|
263
260
|
|
264
|
-
header Grape::Http::Headers::ALLOW,
|
261
|
+
header Grape::Http::Headers::ALLOW, allow_header_value
|
265
262
|
response_object = ''
|
266
263
|
status 204
|
267
264
|
else
|
@@ -287,59 +284,6 @@ module Grape
|
|
287
284
|
end
|
288
285
|
end
|
289
286
|
|
290
|
-
def build_stack(helpers)
|
291
|
-
stack = Grape::Middleware::Stack.new
|
292
|
-
|
293
|
-
content_types = namespace_stackable_with_hash(:content_types)
|
294
|
-
format = namespace_inheritable(:format)
|
295
|
-
|
296
|
-
stack.use Rack::Head
|
297
|
-
stack.use Class.new(Grape::Middleware::Error),
|
298
|
-
helpers: helpers,
|
299
|
-
format: format,
|
300
|
-
content_types: content_types,
|
301
|
-
default_status: namespace_inheritable(:default_error_status),
|
302
|
-
rescue_all: namespace_inheritable(:rescue_all),
|
303
|
-
rescue_grape_exceptions: namespace_inheritable(:rescue_grape_exceptions),
|
304
|
-
default_error_formatter: namespace_inheritable(:default_error_formatter),
|
305
|
-
error_formatters: namespace_stackable_with_hash(:error_formatters),
|
306
|
-
rescue_options: namespace_stackable_with_hash(:rescue_options),
|
307
|
-
rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers),
|
308
|
-
base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers),
|
309
|
-
all_rescue_handler: namespace_inheritable(:all_rescue_handler),
|
310
|
-
grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
|
311
|
-
|
312
|
-
stack.concat namespace_stackable(:middleware)
|
313
|
-
|
314
|
-
if namespace_inheritable(:version).present?
|
315
|
-
stack.use Grape::Middleware::Versioner.using(namespace_inheritable(:version_options)[:using]),
|
316
|
-
versions: namespace_inheritable(:version).flatten,
|
317
|
-
version_options: namespace_inheritable(:version_options),
|
318
|
-
prefix: namespace_inheritable(:root_prefix),
|
319
|
-
mount_path: namespace_stackable(:mount_path).first
|
320
|
-
end
|
321
|
-
|
322
|
-
stack.use Grape::Middleware::Formatter,
|
323
|
-
format: format,
|
324
|
-
default_format: namespace_inheritable(:default_format) || :txt,
|
325
|
-
content_types: content_types,
|
326
|
-
formatters: namespace_stackable_with_hash(:formatters),
|
327
|
-
parsers: namespace_stackable_with_hash(:parsers)
|
328
|
-
|
329
|
-
builder = stack.build
|
330
|
-
builder.run ->(env) { env[Grape::Env::API_ENDPOINT].run }
|
331
|
-
builder.to_app
|
332
|
-
end
|
333
|
-
|
334
|
-
def build_helpers
|
335
|
-
helpers = namespace_stackable(:helpers)
|
336
|
-
return if helpers.empty?
|
337
|
-
|
338
|
-
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
|
339
|
-
end
|
340
|
-
|
341
|
-
private :build_stack, :build_helpers
|
342
|
-
|
343
287
|
def execute
|
344
288
|
@block&.call(self)
|
345
289
|
end
|
@@ -411,7 +355,7 @@ module Grape
|
|
411
355
|
return enum_for(:validations) unless block_given?
|
412
356
|
|
413
357
|
route_setting(:saved_validations)&.each do |saved_validation|
|
414
|
-
yield Grape::Validations::ValidatorFactory.create_validator(
|
358
|
+
yield Grape::Validations::ValidatorFactory.create_validator(saved_validation)
|
415
359
|
end
|
416
360
|
end
|
417
361
|
|
@@ -419,5 +363,58 @@ module Grape
|
|
419
363
|
options[:options_route_enabled] &&
|
420
364
|
env[Rack::REQUEST_METHOD] == Rack::OPTIONS
|
421
365
|
end
|
366
|
+
|
367
|
+
private
|
368
|
+
|
369
|
+
def build_stack(helpers)
|
370
|
+
stack = Grape::Middleware::Stack.new
|
371
|
+
|
372
|
+
content_types = namespace_stackable_with_hash(:content_types)
|
373
|
+
format = namespace_inheritable(:format)
|
374
|
+
|
375
|
+
stack.use Rack::Head
|
376
|
+
stack.use Class.new(Grape::Middleware::Error),
|
377
|
+
helpers: helpers,
|
378
|
+
format: format,
|
379
|
+
content_types: content_types,
|
380
|
+
default_status: namespace_inheritable(:default_error_status),
|
381
|
+
rescue_all: namespace_inheritable(:rescue_all),
|
382
|
+
rescue_grape_exceptions: namespace_inheritable(:rescue_grape_exceptions),
|
383
|
+
default_error_formatter: namespace_inheritable(:default_error_formatter),
|
384
|
+
error_formatters: namespace_stackable_with_hash(:error_formatters),
|
385
|
+
rescue_options: namespace_stackable_with_hash(:rescue_options),
|
386
|
+
rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers),
|
387
|
+
base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers),
|
388
|
+
all_rescue_handler: namespace_inheritable(:all_rescue_handler),
|
389
|
+
grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
|
390
|
+
|
391
|
+
stack.concat namespace_stackable(:middleware)
|
392
|
+
|
393
|
+
if namespace_inheritable(:version).present?
|
394
|
+
stack.use Grape::Middleware::Versioner.using(namespace_inheritable(:version_options)[:using]),
|
395
|
+
versions: namespace_inheritable(:version).flatten,
|
396
|
+
version_options: namespace_inheritable(:version_options),
|
397
|
+
prefix: namespace_inheritable(:root_prefix),
|
398
|
+
mount_path: namespace_stackable(:mount_path).first
|
399
|
+
end
|
400
|
+
|
401
|
+
stack.use Grape::Middleware::Formatter,
|
402
|
+
format: format,
|
403
|
+
default_format: namespace_inheritable(:default_format) || :txt,
|
404
|
+
content_types: content_types,
|
405
|
+
formatters: namespace_stackable_with_hash(:formatters),
|
406
|
+
parsers: namespace_stackable_with_hash(:parsers)
|
407
|
+
|
408
|
+
builder = stack.build
|
409
|
+
builder.run ->(env) { env[Grape::Env::API_ENDPOINT].run }
|
410
|
+
builder.to_app
|
411
|
+
end
|
412
|
+
|
413
|
+
def build_helpers
|
414
|
+
helpers = namespace_stackable(:helpers)
|
415
|
+
return if helpers.empty?
|
416
|
+
|
417
|
+
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
|
418
|
+
end
|
422
419
|
end
|
423
420
|
end
|
@@ -2,36 +2,66 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
class Base
|
6
|
+
class << self
|
7
|
+
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
|
8
|
+
merge_backtrace = backtrace.present? && options.dig(:rescue_options, :backtrace)
|
9
|
+
merge_original_exception = original_exception && options.dig(:rescue_options, :original_exception)
|
10
|
+
|
11
|
+
wrapped_message = wrap_message(present(message, env))
|
12
|
+
if wrapped_message.is_a?(Hash)
|
13
|
+
wrapped_message[:backtrace] = backtrace if merge_backtrace
|
14
|
+
wrapped_message[:original_exception] = original_exception.inspect if merge_original_exception
|
15
|
+
end
|
16
|
+
|
17
|
+
format_structured_message(wrapped_message)
|
12
18
|
end
|
13
19
|
|
14
|
-
|
20
|
+
def present(message, env)
|
21
|
+
present_options = {}
|
22
|
+
presented_message = message
|
23
|
+
if presented_message.is_a?(Hash)
|
24
|
+
presented_message = presented_message.dup
|
25
|
+
present_options[:with] = presented_message.delete(:with)
|
26
|
+
end
|
27
|
+
|
28
|
+
presenter = env[Grape::Env::API_ENDPOINT].entity_class_for_obj(presented_message, present_options)
|
29
|
+
|
30
|
+
unless presenter || env[Grape::Env::GRAPE_ROUTING_ARGS].nil?
|
31
|
+
# env['api.endpoint'].route does not work when the error occurs within a middleware
|
32
|
+
# the Endpoint does not have a valid env at this moment
|
33
|
+
http_codes = env[Grape::Env::GRAPE_ROUTING_ARGS][:route_info].http_codes || []
|
34
|
+
|
35
|
+
found_code = http_codes.find do |http_code|
|
36
|
+
(http_code[0].to_i == env[Grape::Env::API_ENDPOINT].status) && http_code[2].respond_to?(:represent)
|
37
|
+
end if env[Grape::Env::API_ENDPOINT].request
|
15
38
|
|
16
|
-
|
17
|
-
|
18
|
-
# the Endpoint does not have a valid env at this moment
|
19
|
-
http_codes = env[Grape::Env::GRAPE_ROUTING_ARGS][:route_info].http_codes || []
|
39
|
+
presenter = found_code[2] if found_code
|
40
|
+
end
|
20
41
|
|
21
|
-
|
22
|
-
|
23
|
-
|
42
|
+
if presenter
|
43
|
+
embeds = { env: env }
|
44
|
+
embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
|
45
|
+
presented_message = presenter.represent(presented_message, embeds).serializable_hash
|
46
|
+
end
|
24
47
|
|
25
|
-
|
48
|
+
presented_message
|
26
49
|
end
|
27
50
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
51
|
+
def wrap_message(message)
|
52
|
+
return message if message.is_a?(Hash)
|
53
|
+
|
54
|
+
{ message: message }
|
55
|
+
end
|
56
|
+
|
57
|
+
def format_structured_message(_structured_message)
|
58
|
+
raise NotImplementedError
|
32
59
|
end
|
33
60
|
|
34
|
-
|
61
|
+
def inherited(klass)
|
62
|
+
super
|
63
|
+
ErrorFormatter.register(klass)
|
64
|
+
end
|
35
65
|
end
|
36
66
|
end
|
37
67
|
end
|
@@ -2,28 +2,19 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
6
|
-
extend Base
|
7
|
-
|
5
|
+
class Json < Base
|
8
6
|
class << self
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
result = merge_rescue_options(result, backtrace, options, original_exception) if result.is_a?(Hash)
|
13
|
-
|
14
|
-
::Grape::Json.dump(result)
|
7
|
+
def format_structured_message(structured_message)
|
8
|
+
::Grape::Json.dump(structured_message)
|
15
9
|
end
|
16
10
|
|
17
11
|
private
|
18
12
|
|
19
13
|
def wrap_message(message)
|
20
|
-
if message.is_a?(Hash)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
else
|
25
|
-
{ error: ensure_utf8(message) }
|
26
|
-
end
|
14
|
+
return message if message.is_a?(Hash)
|
15
|
+
return message.as_json if message.is_a?(Exceptions::ValidationErrors)
|
16
|
+
|
17
|
+
{ error: ensure_utf8(message) }
|
27
18
|
end
|
28
19
|
|
29
20
|
def ensure_utf8(message)
|
@@ -31,14 +22,6 @@ module Grape
|
|
31
22
|
|
32
23
|
message.encode('UTF-8', invalid: :replace, undef: :replace)
|
33
24
|
end
|
34
|
-
|
35
|
-
def merge_rescue_options(result, backtrace, options, original_exception)
|
36
|
-
rescue_options = options[:rescue_options] || {}
|
37
|
-
result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
|
38
|
-
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
|
39
|
-
|
40
|
-
result
|
41
|
-
end
|
42
25
|
end
|
43
26
|
end
|
44
27
|
end
|
@@ -2,26 +2,19 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
if rescue_options[:original_exception] && original_exception
|
20
|
-
final_result << 'original exception:'
|
21
|
-
final_result << original_exception.inspect
|
22
|
-
end
|
23
|
-
end.join("\r\n ")
|
24
|
-
end
|
5
|
+
class Txt < Base
|
6
|
+
def self.format_structured_message(structured_message)
|
7
|
+
message = structured_message[:message] || Grape::Json.dump(structured_message)
|
8
|
+
Array.wrap(message).tap do |final_message|
|
9
|
+
if structured_message.key?(:backtrace)
|
10
|
+
final_message << 'backtrace:'
|
11
|
+
final_message.concat(structured_message[:backtrace])
|
12
|
+
end
|
13
|
+
if structured_message.key?(:original_exception)
|
14
|
+
final_message << 'original exception:'
|
15
|
+
final_message << structured_message[:original_exception]
|
16
|
+
end
|
17
|
+
end.join("\r\n ")
|
25
18
|
end
|
26
19
|
end
|
27
20
|
end
|
@@ -2,19 +2,9 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
|
10
|
-
message = present(message, env)
|
11
|
-
|
12
|
-
result = message.is_a?(Hash) ? message : { message: message }
|
13
|
-
rescue_options = options[:rescue_options] || {}
|
14
|
-
result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
|
15
|
-
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
|
16
|
-
result.respond_to?(:to_xml) ? result.to_xml(root: :error) : result.to_s
|
17
|
-
end
|
5
|
+
class Xml < Base
|
6
|
+
def self.format_structured_message(structured_message)
|
7
|
+
structured_message.respond_to?(:to_xml) ? structured_message.to_xml(root: :error) : structured_message.to_s
|
18
8
|
end
|
19
9
|
end
|
20
10
|
end
|
@@ -2,22 +2,14 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
5
|
+
extend Grape::Util::Registry
|
6
6
|
|
7
|
-
|
8
|
-
serializable_hash: Grape::ErrorFormatter::Json,
|
9
|
-
json: Grape::ErrorFormatter::Json,
|
10
|
-
jsonapi: Grape::ErrorFormatter::Json,
|
11
|
-
txt: Grape::ErrorFormatter::Txt,
|
12
|
-
xml: Grape::ErrorFormatter::Xml
|
13
|
-
}.freeze
|
7
|
+
module_function
|
14
8
|
|
15
9
|
def formatter_for(format, error_formatters = nil, default_error_formatter = nil)
|
16
|
-
|
17
|
-
end
|
10
|
+
return error_formatters[format] if error_formatters&.key?(format)
|
18
11
|
|
19
|
-
|
20
|
-
error_formatters&.key?(format) ? error_formatters[format] : DEFAULTS[format]
|
12
|
+
registry[format] || default_error_formatter || Grape::ErrorFormatter::Txt
|
21
13
|
end
|
22
14
|
end
|
23
15
|
end
|
@@ -9,7 +9,7 @@ module Grape
|
|
9
9
|
|
10
10
|
attr_reader :status, :headers
|
11
11
|
|
12
|
-
def initialize(status: nil, message: nil, headers: nil
|
12
|
+
def initialize(status: nil, message: nil, headers: nil)
|
13
13
|
super(message)
|
14
14
|
|
15
15
|
@status = status
|
@@ -26,42 +26,32 @@ module Grape
|
|
26
26
|
# if BASE_ATTRIBUTES_KEY.key respond to a string message, then short_message is returned
|
27
27
|
# if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
|
28
28
|
def compose_message(key, **attributes)
|
29
|
-
short_message = translate_message(key,
|
30
|
-
|
31
|
-
@problem = problem(key, **attributes)
|
32
|
-
@summary = summary(key, **attributes)
|
33
|
-
@resolution = resolution(key, **attributes)
|
34
|
-
[['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].each_with_object(+'') do |detail_array, message|
|
35
|
-
message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
|
36
|
-
message
|
37
|
-
end
|
38
|
-
else
|
39
|
-
short_message
|
40
|
-
end
|
41
|
-
end
|
29
|
+
short_message = translate_message(key, attributes)
|
30
|
+
return short_message unless short_message.is_a?(Hash)
|
42
31
|
|
43
|
-
|
44
|
-
|
32
|
+
each_steps(key, attributes).with_object(+'') do |detail_array, message|
|
33
|
+
message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
|
34
|
+
end
|
45
35
|
end
|
46
36
|
|
47
|
-
def
|
48
|
-
|
49
|
-
end
|
37
|
+
def each_steps(key, attributes)
|
38
|
+
return enum_for(:each_steps, key, attributes) unless block_given?
|
50
39
|
|
51
|
-
|
52
|
-
translate_message(:"#{key}.
|
40
|
+
yield 'Problem', translate_message(:"#{key}.problem", attributes)
|
41
|
+
yield 'Summary', translate_message(:"#{key}.summary", attributes)
|
42
|
+
yield 'Resolution', translate_message(:"#{key}.resolution", attributes)
|
53
43
|
end
|
54
44
|
|
55
|
-
def translate_attributes(keys,
|
45
|
+
def translate_attributes(keys, options = {})
|
56
46
|
keys.map do |key|
|
57
|
-
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key
|
47
|
+
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", options.merge(default: key.to_s))
|
58
48
|
end.join(', ')
|
59
49
|
end
|
60
50
|
|
61
|
-
def translate_message(key,
|
51
|
+
def translate_message(key, options = {})
|
62
52
|
case key
|
63
53
|
when Symbol
|
64
|
-
translate("#{BASE_MESSAGES_KEY}.#{key}", default: ''
|
54
|
+
translate("#{BASE_MESSAGES_KEY}.#{key}", options.merge(default: ''))
|
65
55
|
when Proc
|
66
56
|
key.call
|
67
57
|
else
|
@@ -69,14 +59,12 @@ module Grape
|
|
69
59
|
end
|
70
60
|
end
|
71
61
|
|
72
|
-
def translate(key,
|
73
|
-
options = options.dup
|
74
|
-
options[:default] &&= options[:default].to_s
|
62
|
+
def translate(key, options)
|
75
63
|
message = ::I18n.translate(key, **options)
|
76
|
-
message.presence || fallback_message(key,
|
64
|
+
message.presence || fallback_message(key, options)
|
77
65
|
end
|
78
66
|
|
79
|
-
def fallback_message(key,
|
67
|
+
def fallback_message(key, options)
|
80
68
|
if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
|
81
69
|
key
|
82
70
|
else
|
@@ -2,16 +2,17 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Exceptions
|
5
|
-
class Validation <
|
5
|
+
class Validation < Base
|
6
6
|
attr_accessor :params, :message_key
|
7
7
|
|
8
|
-
def initialize(params:, message: nil,
|
8
|
+
def initialize(params:, message: nil, status: nil, headers: nil)
|
9
9
|
@params = params
|
10
10
|
if message
|
11
11
|
@message_key = message if message.is_a?(Symbol)
|
12
|
-
|
12
|
+
message = translate_message(message)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
|
+
super(status: status, message: message, headers: headers)
|
15
16
|
end
|
16
17
|
|
17
18
|
# Remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Exceptions
|
5
|
-
class ValidationErrors <
|
5
|
+
class ValidationErrors < Base
|
6
6
|
ERRORS_FORMAT_KEY = 'grape.errors.format'
|
7
7
|
DEFAULT_ERRORS_FORMAT = '%<attributes>s %<message>s'
|
8
8
|
|
@@ -10,7 +10,7 @@ module Grape
|
|
10
10
|
|
11
11
|
attr_reader :errors
|
12
12
|
|
13
|
-
def initialize(errors: [], headers: {}
|
13
|
+
def initialize(errors: [], headers: {})
|
14
14
|
@errors = errors.group_by(&:params)
|
15
15
|
super(message: full_messages.join(', '), status: 400, headers: headers)
|
16
16
|
end
|
data/lib/grape/formatter/json.rb
CHANGED
@@ -2,13 +2,11 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Formatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
return object.to_json if object.respond_to?(:to_json)
|
5
|
+
class Json < Base
|
6
|
+
def self.call(object, _env)
|
7
|
+
return object.to_json if object.respond_to?(:to_json)
|
9
8
|
|
10
|
-
|
11
|
-
end
|
9
|
+
::Grape::Json.dump(object)
|
12
10
|
end
|
13
11
|
end
|
14
12
|
end
|
data/lib/grape/formatter/txt.rb
CHANGED
@@ -2,11 +2,9 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Formatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
|
9
|
-
end
|
5
|
+
class Txt < Base
|
6
|
+
def self.call(object, _env)
|
7
|
+
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
|
10
8
|
end
|
11
9
|
end
|
12
10
|
end
|
data/lib/grape/formatter/xml.rb
CHANGED
@@ -2,13 +2,11 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Formatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
return object.to_xml if object.respond_to?(:to_xml)
|
5
|
+
class Xml < Base
|
6
|
+
def self.call(object, _env)
|
7
|
+
return object.to_xml if object.respond_to?(:to_xml)
|
9
8
|
|
10
|
-
|
11
|
-
end
|
9
|
+
raise Grape::Exceptions::InvalidFormatter.new(object.class, 'xml')
|
12
10
|
end
|
13
11
|
end
|
14
12
|
end
|