grape 2.4.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +109 -0
- data/CONTRIBUTING.md +2 -10
- data/README.md +137 -181
- data/UPGRADING.md +154 -0
- data/grape.gemspec +4 -4
- data/lib/grape/api/instance.rb +51 -104
- data/lib/grape/api.rb +29 -42
- data/lib/grape/content_types.rb +1 -4
- data/lib/grape/declared_params_handler.rb +118 -0
- data/lib/grape/dry_types.rb +48 -4
- data/lib/grape/dsl/callbacks.rb +8 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +8 -67
- data/lib/grape/dsl/helpers.rb +59 -64
- data/lib/grape/dsl/inside_route.rb +28 -189
- data/lib/grape/dsl/logger.rb +3 -6
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +24 -51
- data/lib/grape/dsl/request_response.rb +136 -139
- data/lib/grape/dsl/routing.rb +240 -200
- data/lib/grape/dsl/settings.rb +23 -135
- data/lib/grape/dsl/validations.rb +38 -44
- data/lib/grape/endpoint.rb +169 -205
- data/lib/grape/error_formatter/base.rb +4 -2
- data/lib/grape/exceptions/base.rb +19 -45
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_message_body.rb +1 -1
- data/lib/grape/exceptions/invalid_version_header.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/method_not_allowed.rb +1 -1
- data/lib/grape/exceptions/missing_group_type.rb +0 -2
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/request_error.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +1 -1
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_params_builder.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
- data/lib/grape/exceptions/validation.rb +7 -4
- data/lib/grape/exceptions/validation_errors.rb +13 -7
- data/lib/grape/locale/en.yml +0 -5
- data/lib/grape/middleware/auth/base.rb +2 -0
- data/lib/grape/middleware/auth/dsl.rb +9 -10
- data/lib/grape/middleware/base.rb +6 -4
- data/lib/grape/middleware/error.rb +4 -14
- data/lib/grape/middleware/formatter.rb +11 -7
- data/lib/grape/middleware/stack.rb +3 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -3
- data/lib/grape/middleware/versioner/base.rb +42 -40
- data/lib/grape/middleware/versioner/header.rb +2 -18
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +2 -2
- data/lib/grape/namespace.rb +15 -8
- data/lib/grape/params_builder/base.rb +2 -0
- data/lib/grape/params_builder.rb +2 -19
- data/lib/grape/request.rb +2 -10
- data/lib/grape/router/base_route.rb +14 -5
- data/lib/grape/router/greedy_route.rb +11 -5
- data/lib/grape/router/pattern.rb +6 -20
- data/lib/grape/router/route.rb +7 -11
- data/lib/grape/router.rb +42 -65
- data/lib/grape/util/api_description.rb +58 -0
- data/lib/grape/util/base_inheritable.rb +5 -2
- data/lib/grape/util/cache.rb +1 -0
- data/lib/grape/util/deep_freeze.rb +35 -0
- data/lib/grape/util/inheritable_setting.rb +8 -1
- data/lib/grape/util/media_type.rb +2 -2
- data/lib/grape/util/registry.rb +1 -1
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +35 -20
- data/lib/grape/validations/contract_scope.rb +2 -8
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/param_scope_tracker.rb +57 -0
- data/lib/grape/validations/params_documentation.rb +50 -0
- data/lib/grape/validations/params_scope.rb +147 -156
- data/lib/grape/validations/single_attribute_iterator.rb +2 -2
- data/lib/grape/validations/types/array_coercer.rb +2 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -11
- data/lib/grape/validations/types/primitive_coercer.rb +1 -28
- data/lib/grape/validations/types.rb +10 -25
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
- data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
- data/lib/grape/validations/validators/base.rb +95 -25
- data/lib/grape/validations/validators/coerce_validator.rb +15 -35
- data/lib/grape/validations/validators/contract_scope_validator.rb +9 -5
- data/lib/grape/validations/validators/default_validator.rb +12 -18
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
- data/lib/grape/validations/validators/except_values_validator.rb +13 -4
- data/lib/grape/validations/validators/length_validator.rb +21 -22
- data/lib/grape/validations/validators/multiple_params_base.rb +5 -5
- data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
- data/lib/grape/validations/validators/presence_validator.rb +4 -2
- data/lib/grape/validations/validators/regexp_validator.rb +11 -3
- data/lib/grape/validations/validators/same_as_validator.rb +6 -15
- data/lib/grape/validations/validators/values_validator.rb +29 -21
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +29 -23
- metadata +31 -26
- data/lib/grape/api/helpers.rb +0 -9
- data/lib/grape/dsl/api.rb +0 -17
- data/lib/grape/dsl/configuration.rb +0 -15
- data/lib/grape/exceptions/conflicting_types.rb +0 -11
- data/lib/grape/exceptions/empty_message_body.rb +0 -11
- data/lib/grape/exceptions/invalid_parameters.rb +0 -11
- data/lib/grape/exceptions/missing_option.rb +0 -11
- data/lib/grape/exceptions/too_deep_parameters.rb +0 -11
- data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
- data/lib/grape/exceptions/unknown_options.rb +0 -11
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +0 -24
- data/lib/grape/extensions/hash.rb +0 -27
- data/lib/grape/extensions/hashie/mash.rb +0 -24
- data/lib/grape/types/invalid_value.rb +0 -8
- data/lib/grape/util/strict_hash_configuration.rb +0 -108
- data/lib/grape/validations/attributes_doc.rb +0 -60
- data/lib/grape/validations/validator_factory.rb +0 -15
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class Base < StandardError
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
include Grape::Util::Translation
|
|
7
|
+
|
|
8
|
+
MESSAGE_STEPS = %w[problem summary resolution].to_h { |s| [s, s.capitalize] }.freeze
|
|
9
9
|
|
|
10
10
|
attr_reader :status, :headers
|
|
11
11
|
|
|
@@ -17,58 +17,32 @@ module Grape
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def [](index)
|
|
20
|
-
|
|
20
|
+
__send__ index
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
private
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
|
|
28
|
-
def compose_message(key, **attributes)
|
|
29
|
-
short_message = translate_message(key, attributes)
|
|
25
|
+
def compose_message(key, **)
|
|
26
|
+
short_message = translate_message(key, **)
|
|
30
27
|
return short_message unless short_message.is_a?(Hash)
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def each_steps(key, attributes)
|
|
38
|
-
return enum_for(:each_steps, key, attributes) unless block_given?
|
|
39
|
-
|
|
40
|
-
yield 'Problem', translate_message(:"#{key}.problem", attributes)
|
|
41
|
-
yield 'Summary', translate_message(:"#{key}.summary", attributes)
|
|
42
|
-
yield 'Resolution', translate_message(:"#{key}.resolution", attributes)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def translate_attributes(keys, options = {})
|
|
46
|
-
keys.map do |key|
|
|
47
|
-
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", options.merge(default: key.to_s))
|
|
48
|
-
end.join(', ')
|
|
29
|
+
MESSAGE_STEPS.filter_map do |step, label|
|
|
30
|
+
detail = translate_message(:"#{key}.#{step}", **)
|
|
31
|
+
"\n#{label}:\n #{detail}" if detail.present?
|
|
32
|
+
end.join
|
|
49
33
|
end
|
|
50
34
|
|
|
51
|
-
def translate_message(
|
|
52
|
-
case
|
|
35
|
+
def translate_message(translation_key, **)
|
|
36
|
+
case translation_key
|
|
53
37
|
when Symbol
|
|
54
|
-
translate(
|
|
38
|
+
translate(translation_key, **)
|
|
39
|
+
when Hash
|
|
40
|
+
translation_key => { key:, **opts }
|
|
41
|
+
translate(key, **opts)
|
|
55
42
|
when Proc
|
|
56
|
-
|
|
57
|
-
else
|
|
58
|
-
key
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def translate(key, options)
|
|
63
|
-
message = ::I18n.translate(key, **options)
|
|
64
|
-
message.presence || fallback_message(key, options)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def fallback_message(key, options)
|
|
68
|
-
if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
|
|
69
|
-
key
|
|
43
|
+
translation_key.call
|
|
70
44
|
else
|
|
71
|
-
|
|
45
|
+
translation_key
|
|
72
46
|
end
|
|
73
47
|
end
|
|
74
48
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class IncompatibleOptionValues < Base
|
|
6
6
|
def initialize(option1, value1, option2, value2)
|
|
7
|
-
super(message: compose_message(:incompatible_option_values, option1
|
|
7
|
+
super(message: compose_message(:incompatible_option_values, option1:, value1:, option2:, value2:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidAcceptHeader < Base
|
|
6
6
|
def initialize(message, headers)
|
|
7
|
-
super(message: compose_message(:invalid_accept_header, message:
|
|
7
|
+
super(message: compose_message(:invalid_accept_header, message:), status: 406, headers:)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidFormatter < Base
|
|
6
6
|
def initialize(klass, to_format)
|
|
7
|
-
super(message: compose_message(:invalid_formatter, klass
|
|
7
|
+
super(message: compose_message(:invalid_formatter, klass:, to_format:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidMessageBody < Base
|
|
6
6
|
def initialize(body_format)
|
|
7
|
-
super(message: compose_message(:invalid_message_body, body_format:
|
|
7
|
+
super(message: compose_message(:invalid_message_body, body_format:), status: 400)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidVersionHeader < Base
|
|
6
6
|
def initialize(message, headers)
|
|
7
|
-
super(message: compose_message(:invalid_version_header, message:
|
|
7
|
+
super(message: compose_message(:invalid_version_header, message:), status: 406, headers:)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidVersionerOption < Base
|
|
6
6
|
def initialize(strategy)
|
|
7
|
-
super(message: compose_message(:invalid_versioner_option, strategy:
|
|
7
|
+
super(message: compose_message(:invalid_versioner_option, strategy:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class UnknownParamsBuilder < Base
|
|
6
6
|
def initialize(params_builder_type)
|
|
7
|
-
super(message: compose_message(:unknown_params_builder, params_builder_type:
|
|
7
|
+
super(message: compose_message(:unknown_params_builder, params_builder_type:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class UnknownValidator < Base
|
|
6
6
|
def initialize(validator_type)
|
|
7
|
-
super(message: compose_message(:unknown_validator, validator_type:
|
|
7
|
+
super(message: compose_message(:unknown_validator, validator_type:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class Validation < Base
|
|
6
|
-
|
|
6
|
+
attr_reader :params, :message_key
|
|
7
7
|
|
|
8
8
|
def initialize(params:, message: nil, status: nil, headers: nil)
|
|
9
|
-
@params = params
|
|
9
|
+
@params = Array(params)
|
|
10
10
|
if message
|
|
11
|
-
@message_key =
|
|
11
|
+
@message_key = case message
|
|
12
|
+
when Symbol then message
|
|
13
|
+
when Hash then message[:key]
|
|
14
|
+
end
|
|
12
15
|
message = translate_message(message)
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
super(status
|
|
18
|
+
super(status:, message:, headers:)
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
# Remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
|
@@ -3,16 +3,13 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class ValidationErrors < Base
|
|
6
|
-
ERRORS_FORMAT_KEY = 'grape.errors.format'
|
|
7
|
-
DEFAULT_ERRORS_FORMAT = '%<attributes>s %<message>s'
|
|
8
|
-
|
|
9
6
|
include Enumerable
|
|
10
7
|
|
|
11
8
|
attr_reader :errors
|
|
12
9
|
|
|
13
10
|
def initialize(errors: [], headers: {})
|
|
14
11
|
@errors = errors.group_by(&:params)
|
|
15
|
-
super(message: full_messages.join(', '), status: 400, headers:
|
|
12
|
+
super(message: full_messages.join(', '), status: 400, headers:)
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def each
|
|
@@ -38,9 +35,10 @@ module Grape
|
|
|
38
35
|
|
|
39
36
|
def full_messages
|
|
40
37
|
messages = map do |attributes, error|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
translate(
|
|
39
|
+
:format,
|
|
40
|
+
scope: 'grape.errors',
|
|
41
|
+
default: '%<attributes>s %<message>s',
|
|
44
42
|
attributes: translate_attributes(attributes),
|
|
45
43
|
message: error.message
|
|
46
44
|
)
|
|
@@ -48,6 +46,14 @@ module Grape
|
|
|
48
46
|
messages.uniq!
|
|
49
47
|
messages
|
|
50
48
|
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def translate_attributes(keys)
|
|
53
|
+
keys.map do |key|
|
|
54
|
+
translate(key, scope: 'grape.errors.attributes', default: key.to_s)
|
|
55
|
+
end.join(', ')
|
|
56
|
+
end
|
|
51
57
|
end
|
|
52
58
|
end
|
|
53
59
|
end
|
data/lib/grape/locale/en.yml
CHANGED
|
@@ -8,8 +8,6 @@ en:
|
|
|
8
8
|
at_least_one: 'are missing, at least one parameter must be provided'
|
|
9
9
|
blank: 'is empty'
|
|
10
10
|
coerce: 'is invalid'
|
|
11
|
-
conflicting_types: 'query params contains conflicting types'
|
|
12
|
-
empty_message_body: 'empty message body supplied with %{body_format} content-type'
|
|
13
11
|
exactly_one: 'are missing, exactly one parameter must be provided'
|
|
14
12
|
except_values: 'has a value not allowed'
|
|
15
13
|
incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
|
|
@@ -20,7 +18,6 @@ en:
|
|
|
20
18
|
invalid_message_body:
|
|
21
19
|
problem: 'message body does not match declared format'
|
|
22
20
|
resolution: 'when specifying %{body_format} as content-type, you must pass valid %{body_format} in the request''s ''body'' '
|
|
23
|
-
invalid_parameters: 'query params contains invalid format or byte sequence'
|
|
24
21
|
invalid_response: 'Invalid response'
|
|
25
22
|
invalid_version_header:
|
|
26
23
|
problem: 'invalid version header'
|
|
@@ -48,8 +45,6 @@ en:
|
|
|
48
45
|
presence: 'is missing'
|
|
49
46
|
regexp: 'is invalid'
|
|
50
47
|
same_as: 'is not the same as %{parameter}'
|
|
51
|
-
too_deep_parameters: 'query params are recursively nested over the specified limit (%{limit})'
|
|
52
|
-
too_many_multipart_files: 'the number of uploaded files exceeded the system''s configured limit (%{limit})'
|
|
53
48
|
unknown_auth_strategy: 'unknown auth strategy: %{strategy}'
|
|
54
49
|
unknown_options: 'unknown options: %{options}'
|
|
55
50
|
unknown_parameter: 'unknown parameter: %{param}'
|
|
@@ -6,6 +6,8 @@ module Grape
|
|
|
6
6
|
class Base < Grape::Middleware::Base
|
|
7
7
|
def initialize(app, **options)
|
|
8
8
|
super
|
|
9
|
+
return unless options.key?(:type)
|
|
10
|
+
|
|
9
11
|
@auth_strategy = Grape::Middleware::Auth::Strategies[options[:type]].tap do |auth_strategy|
|
|
10
12
|
raise Grape::Exceptions::UnknownAuthStrategy.new(strategy: options[:type]) unless auth_strategy
|
|
11
13
|
end
|
|
@@ -5,24 +5,23 @@ module Grape
|
|
|
5
5
|
module Auth
|
|
6
6
|
module DSL
|
|
7
7
|
def auth(type = nil, options = {}, &block)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
8
|
+
namespace_inheritable = inheritable_setting.namespace_inheritable
|
|
9
|
+
return namespace_inheritable[:auth] unless type
|
|
10
|
+
|
|
11
|
+
namespace_inheritable[:auth] = options.reverse_merge(type: type.to_sym, proc: block)
|
|
12
|
+
use Grape::Middleware::Auth::Base, namespace_inheritable[:auth]
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
# Add HTTP Basic authorization to the API.
|
|
17
16
|
#
|
|
18
17
|
# @param [Hash] options A hash of options.
|
|
19
18
|
# @option options [String] :realm "API Authorization" The HTTP Basic realm.
|
|
20
|
-
def http_basic(options = {}, &
|
|
19
|
+
def http_basic(options = {}, &)
|
|
21
20
|
options[:realm] ||= 'API Authorization'
|
|
22
|
-
auth
|
|
21
|
+
auth(:http_basic, options, &)
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
def http_digest(options = {}, &
|
|
24
|
+
def http_digest(options = {}, &)
|
|
26
25
|
options[:realm] ||= 'API Authorization'
|
|
27
26
|
|
|
28
27
|
if options[:realm].respond_to?(:values_at)
|
|
@@ -31,7 +30,7 @@ module Grape
|
|
|
31
30
|
options[:opaque] ||= 'secret'
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
auth
|
|
33
|
+
auth(:http_digest, options, &)
|
|
35
34
|
end
|
|
36
35
|
end
|
|
37
36
|
end
|
|
@@ -79,10 +79,8 @@ module Grape
|
|
|
79
79
|
|
|
80
80
|
def query_params
|
|
81
81
|
rack_request.GET
|
|
82
|
-
rescue
|
|
83
|
-
raise Grape::Exceptions::
|
|
84
|
-
rescue Rack::Utils::ParameterTypeError
|
|
85
|
-
raise Grape::Exceptions::ConflictingTypes
|
|
82
|
+
rescue *Grape::RACK_ERRORS
|
|
83
|
+
raise Grape::Exceptions::RequestError
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
private
|
|
@@ -109,6 +107,10 @@ module Grape
|
|
|
109
107
|
options
|
|
110
108
|
end
|
|
111
109
|
end
|
|
110
|
+
|
|
111
|
+
def try_scrub(obj)
|
|
112
|
+
obj.respond_to?(:valid_encoding?) && !obj.valid_encoding? ? obj.scrub : obj
|
|
113
|
+
end
|
|
112
114
|
end
|
|
113
115
|
end
|
|
114
116
|
end
|
|
@@ -16,11 +16,6 @@ module Grape
|
|
|
16
16
|
}.freeze
|
|
17
17
|
}.freeze
|
|
18
18
|
|
|
19
|
-
def initialize(app, **options)
|
|
20
|
-
super
|
|
21
|
-
self.class.include(options[:helpers]) if options[:helpers]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
19
|
def call!(env)
|
|
25
20
|
@env = env
|
|
26
21
|
error_response(catch(:error) { return @app.call(@env) })
|
|
@@ -43,8 +38,8 @@ module Grape
|
|
|
43
38
|
throw :error,
|
|
44
39
|
status: 406,
|
|
45
40
|
message: "The requested format '#{format}' is not supported.",
|
|
46
|
-
backtrace
|
|
47
|
-
original_exception:
|
|
41
|
+
backtrace:,
|
|
42
|
+
original_exception:
|
|
48
43
|
end
|
|
49
44
|
|
|
50
45
|
def find_handler(klass)
|
|
@@ -63,7 +58,7 @@ module Grape
|
|
|
63
58
|
h.merge!(error[:headers]) if error[:headers].is_a?(Hash)
|
|
64
59
|
end
|
|
65
60
|
backtrace = error[:backtrace] || error[:original_exception]&.backtrace || []
|
|
66
|
-
original_exception = error.is_a?(Exception) ? error : error[:original_exception]
|
|
61
|
+
original_exception = error.is_a?(Exception) ? error : error[:original_exception]
|
|
67
62
|
rack_response(status, headers, format_message(message, backtrace, original_exception))
|
|
68
63
|
end
|
|
69
64
|
|
|
@@ -103,12 +98,7 @@ module Grape
|
|
|
103
98
|
end
|
|
104
99
|
|
|
105
100
|
def run_rescue_handler(handler, error, endpoint)
|
|
106
|
-
if handler.instance_of?(Symbol)
|
|
107
|
-
raise NoMethodError, "undefined method '#{handler}'" unless respond_to?(handler)
|
|
108
|
-
|
|
109
|
-
handler = public_method(handler)
|
|
110
|
-
end
|
|
111
|
-
|
|
101
|
+
handler = endpoint.public_method(handler) if handler.instance_of?(Symbol)
|
|
112
102
|
response = catch(:error) do
|
|
113
103
|
handler.arity.zero? ? endpoint.instance_exec(&handler) : endpoint.instance_exec(error, &handler)
|
|
114
104
|
end
|
|
@@ -7,6 +7,8 @@ module Grape
|
|
|
7
7
|
default_format: :txt
|
|
8
8
|
}.freeze
|
|
9
9
|
|
|
10
|
+
ALL_MEDIA_TYPES = '*/*'
|
|
11
|
+
|
|
10
12
|
def before
|
|
11
13
|
negotiate_content_type
|
|
12
14
|
read_body_input
|
|
@@ -36,7 +38,7 @@ module Grape
|
|
|
36
38
|
else
|
|
37
39
|
# Allow content-type to be explicitly overwritten
|
|
38
40
|
formatter = fetch_formatter(headers, options)
|
|
39
|
-
bodymap = ActiveSupport::Notifications.instrument('format_response.grape', formatter
|
|
41
|
+
bodymap = ActiveSupport::Notifications.instrument('format_response.grape', formatter:, env:) do
|
|
40
42
|
bodies.collect { |body| formatter.call(body, env) }
|
|
41
43
|
end
|
|
42
44
|
Rack::Response.new(bodymap, status, headers)
|
|
@@ -67,12 +69,14 @@ module Grape
|
|
|
67
69
|
return if input.nil?
|
|
68
70
|
return unless read_body_input?
|
|
69
71
|
|
|
70
|
-
input.
|
|
72
|
+
rewind = input.respond_to?(:rewind)
|
|
73
|
+
|
|
74
|
+
input.rewind if rewind
|
|
71
75
|
body = env[Grape::Env::API_REQUEST_INPUT] = input.read
|
|
72
76
|
begin
|
|
73
77
|
read_rack_input(body)
|
|
74
78
|
ensure
|
|
75
|
-
input.
|
|
79
|
+
input.rewind if rewind
|
|
76
80
|
end
|
|
77
81
|
end
|
|
78
82
|
|
|
@@ -128,17 +132,17 @@ module Grape
|
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
def format_from_extension
|
|
131
|
-
request_path = rack_request.path
|
|
135
|
+
request_path = try_scrub(rack_request.path)
|
|
132
136
|
dot_pos = request_path.rindex('.')
|
|
133
137
|
return unless dot_pos
|
|
134
138
|
|
|
135
|
-
extension = request_path[dot_pos + 1..]
|
|
139
|
+
extension = request_path[(dot_pos + 1)..]
|
|
136
140
|
extension if content_type_for(extension)
|
|
137
141
|
end
|
|
138
142
|
|
|
139
143
|
def format_from_header
|
|
140
|
-
accept_header = env['HTTP_ACCEPT']
|
|
141
|
-
return if accept_header.blank?
|
|
144
|
+
accept_header = try_scrub(env['HTTP_ACCEPT'])
|
|
145
|
+
return if accept_header.blank? || accept_header == ALL_MEDIA_TYPES
|
|
142
146
|
|
|
143
147
|
media_type = Rack::Utils.best_q_match(accept_header, mime_types.keys)
|
|
144
148
|
mime_types[media_type] if media_type
|
|
@@ -6,6 +6,7 @@ module Grape
|
|
|
6
6
|
# It allows to insert and insert after
|
|
7
7
|
class Stack
|
|
8
8
|
extend Forwardable
|
|
9
|
+
|
|
9
10
|
class Middleware
|
|
10
11
|
attr_reader :args, :block, :klass
|
|
11
12
|
|
|
@@ -59,9 +60,9 @@ module Grape
|
|
|
59
60
|
|
|
60
61
|
alias insert_before insert
|
|
61
62
|
|
|
62
|
-
def insert_after(index,
|
|
63
|
+
def insert_after(index, ...)
|
|
63
64
|
index = assert_index(index, :after)
|
|
64
|
-
insert(index + 1,
|
|
65
|
+
insert(index + 1, ...)
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
def use(klass, *args, &block)
|
|
@@ -18,8 +18,8 @@ module Grape
|
|
|
18
18
|
# route.
|
|
19
19
|
class AcceptVersionHeader < Base
|
|
20
20
|
def before
|
|
21
|
-
potential_version = env['HTTP_ACCEPT_VERSION']
|
|
22
|
-
not_acceptable!('Accept-Version header must be set.') if strict
|
|
21
|
+
potential_version = try_scrub(env['HTTP_ACCEPT_VERSION'])
|
|
22
|
+
not_acceptable!('Accept-Version header must be set.') if strict && potential_version.blank?
|
|
23
23
|
|
|
24
24
|
return if potential_version.blank?
|
|
25
25
|
|
|
@@ -30,7 +30,7 @@ module Grape
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
32
|
def not_acceptable!(message)
|
|
33
|
-
throw :error, status: 406, headers: error_headers, message:
|
|
33
|
+
throw :error, status: 406, headers: error_headers, message:
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
end
|