grape 1.8.0 → 4.0.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 +517 -1
- data/CONTRIBUTING.md +19 -11
- data/README.md +841 -545
- data/UPGRADING.md +1553 -7
- data/grape.gemspec +11 -14
- data/lib/grape/api/instance.rb +77 -160
- data/lib/grape/api.rb +75 -107
- data/lib/grape/content_types.rb +67 -9
- data/lib/grape/cookies.rb +28 -25
- data/lib/grape/declared_params_handler.rb +116 -0
- data/lib/grape/dry_types.rb +48 -6
- data/lib/grape/dsl/callbacks.rb +8 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +25 -63
- data/lib/grape/dsl/entity.rb +106 -0
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +83 -64
- data/lib/grape/dsl/inside_route.rb +69 -296
- data/lib/grape/dsl/logger.rb +4 -9
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +88 -94
- data/lib/grape/dsl/request_response.rb +143 -147
- data/lib/grape/dsl/rescue_options.rb +25 -0
- data/lib/grape/dsl/routing.rb +333 -191
- data/lib/grape/dsl/settings.rb +29 -135
- data/lib/grape/dsl/validations.rb +39 -32
- data/lib/grape/dsl/version_options.rb +23 -0
- data/lib/grape/endpoint/options.rb +25 -0
- data/lib/grape/endpoint.rb +319 -269
- data/lib/grape/{util/env.rb → env.rb} +8 -8
- data/lib/grape/error_formatter/base.rb +57 -21
- data/lib/grape/error_formatter/json.rb +13 -15
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +12 -18
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +9 -25
- data/lib/grape/exceptions/base.rb +22 -58
- data/lib/grape/exceptions/error_response.rb +48 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/internal_server_error.rb +16 -0
- 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 +11 -0
- data/lib/grape/exceptions/unknown_error_formatter.rb +11 -0
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- 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 +28 -11
- data/lib/grape/exceptions/validation_array_errors.rb +5 -0
- data/lib/grape/exceptions/validation_errors.rb +22 -26
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +5 -6
- data/lib/grape/formatter/serializable_hash.rb +7 -10
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +7 -25
- data/lib/grape/json.rb +46 -0
- data/lib/grape/locale/en.yml +44 -42
- data/lib/grape/middleware/auth/base.rb +11 -33
- data/lib/grape/middleware/auth/dsl.rb +12 -34
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/base.rb +56 -33
- data/lib/grape/middleware/error.rb +290 -91
- data/lib/grape/middleware/formatter.rb +164 -106
- data/lib/grape/middleware/precomputed_content_types.rb +51 -0
- data/lib/grape/middleware/stack.rb +38 -40
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +66 -0
- data/lib/grape/middleware/versioner/header.rb +44 -129
- data/lib/grape/middleware/versioner/param.rb +4 -25
- data/lib/grape/middleware/versioner/path.rb +48 -25
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/mountable.rb +22 -0
- data/lib/grape/namespace.rb +21 -14
- data/lib/grape/params_builder/base.rb +20 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +15 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +8 -94
- data/lib/grape/precompiled_json.rb +50 -0
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +200 -26
- data/lib/grape/router/base_route.rb +85 -0
- data/lib/grape/router/greedy_route.rb +30 -0
- data/lib/grape/router/mustermann_pattern.rb +44 -0
- data/lib/grape/router/pattern/path.rb +78 -0
- data/lib/grape/router/pattern.rb +77 -35
- data/lib/grape/router/route.rb +79 -60
- data/lib/grape/router.rb +128 -104
- data/lib/grape/serve_stream/file_body.rb +7 -0
- data/lib/grape/serve_stream/sendfile_response.rb +3 -5
- data/lib/grape/serve_stream/stream_response.rb +7 -0
- data/lib/grape/testing.rb +33 -0
- data/lib/grape/util/api_description.rb +67 -0
- data/lib/grape/util/cache.rb +22 -5
- data/lib/grape/util/deep_freeze.rb +34 -0
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/freeze_on_new.rb +20 -0
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +777 -39
- data/lib/grape/util/lazy/base.rb +16 -0
- data/lib/grape/util/lazy/block.rb +22 -0
- data/lib/grape/util/lazy/value.rb +31 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +31 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +74 -0
- data/lib/grape/util/path_normalizer.rb +37 -0
- data/lib/grape/util/registry.rb +37 -0
- data/lib/grape/util/shadowed_rescue_handlers.rb +49 -0
- data/lib/grape/util/stackable_values.rb +40 -16
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +61 -28
- data/lib/grape/validations/coerce_options.rb +21 -0
- data/lib/grape/validations/contract_scope.rb +29 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/oneof_collector.rb +35 -0
- data/lib/grape/validations/param_scope_tracker.rb +62 -0
- data/lib/grape/validations/params_documentation.rb +52 -0
- data/lib/grape/validations/params_scope.rb +223 -306
- data/lib/grape/validations/shared_options.rb +19 -0
- data/lib/grape/validations/single_attribute_iterator.rb +6 -4
- data/lib/grape/validations/types/array_coercer.rb +7 -12
- data/lib/grape/validations/types/custom_type_coercer.rb +47 -85
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +17 -28
- data/lib/grape/validations/types/json.rb +1 -5
- data/lib/grape/validations/types/multiple_type_coercer.rb +5 -3
- data/lib/grape/validations/types/primitive_coercer.rb +14 -35
- data/lib/grape/validations/types/set_coercer.rb +1 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +16 -3
- data/lib/grape/validations/types.rb +29 -54
- data/lib/grape/validations/validations_spec.rb +164 -0
- 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 +118 -37
- data/lib/grape/validations/validators/coerce_validator.rb +26 -38
- data/lib/grape/validations/validators/contract_scope_validator.rb +46 -0
- data/lib/grape/validations/validators/default_validator.rb +13 -16
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
- data/lib/grape/validations/validators/except_values_validator.rb +15 -5
- data/lib/grape/validations/validators/length_validator.rb +50 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +12 -9
- data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
- data/lib/grape/validations/validators/oneof_validator.rb +51 -0
- 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 +7 -15
- data/lib/grape/validations/validators/values_validator.rb +36 -65
- data/lib/grape/validations.rb +8 -21
- data/lib/grape/version.rb +1 -2
- data/lib/grape/xml.rb +17 -0
- data/lib/grape.rb +96 -288
- metadata +83 -294
- data/lib/grape/api/helpers.rb +0 -9
- data/lib/grape/dsl/api.rb +0 -19
- data/lib/grape/dsl/configuration.rb +0 -15
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/exceptions/empty_message_body.rb +0 -11
- data/lib/grape/exceptions/missing_option.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 -27
- data/lib/grape/extensions/hash.rb +0 -22
- data/lib/grape/extensions/hashie/mash.rb +0 -26
- data/lib/grape/http/headers.rb +0 -61
- data/lib/grape/middleware/globals.rb +0 -16
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/types/invalid_value.rb +0 -8
- data/lib/grape/util/base_inheritable.rb +0 -43
- data/lib/grape/util/inheritable_values.rb +0 -31
- data/lib/grape/util/json.rb +0 -12
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/util/reverse_stackable_values.rb +0 -20
- data/lib/grape/util/strict_hash_configuration.rb +0 -108
- data/lib/grape/util/xml.rb +0 -10
- data/lib/grape/validations/attributes_doc.rb +0 -58
- data/lib/grape/validations/types/build_coercer.rb +0 -94
- data/lib/grape/validations/validator_factory.rb +0 -15
- data/spec/grape/api/custom_validations_spec.rb +0 -213
- data/spec/grape/api/deeply_included_options_spec.rb +0 -56
- data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
- data/spec/grape/api/documentation_spec.rb +0 -59
- data/spec/grape/api/inherited_helpers_spec.rb +0 -114
- data/spec/grape/api/instance_spec.rb +0 -103
- data/spec/grape/api/invalid_format_spec.rb +0 -45
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
- data/spec/grape/api/nested_helpers_spec.rb +0 -50
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
- data/spec/grape/api/parameters_modification_spec.rb +0 -41
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
- data/spec/grape/api/recognize_path_spec.rb +0 -21
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
- data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
- data/spec/grape/api/shared_helpers_spec.rb +0 -36
- data/spec/grape/api_remount_spec.rb +0 -509
- data/spec/grape/api_spec.rb +0 -4356
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -98
- data/spec/grape/dsl/headers_spec.rb +0 -62
- data/spec/grape/dsl/helpers_spec.rb +0 -100
- data/spec/grape/dsl/inside_route_spec.rb +0 -531
- data/spec/grape/dsl/logger_spec.rb +0 -24
- data/spec/grape/dsl/middleware_spec.rb +0 -60
- data/spec/grape/dsl/parameters_spec.rb +0 -180
- data/spec/grape/dsl/request_response_spec.rb +0 -225
- data/spec/grape/dsl/routing_spec.rb +0 -275
- data/spec/grape/dsl/settings_spec.rb +0 -261
- data/spec/grape/dsl/validations_spec.rb +0 -55
- data/spec/grape/endpoint/declared_spec.rb +0 -846
- data/spec/grape/endpoint_spec.rb +0 -1085
- data/spec/grape/entity_spec.rb +0 -336
- data/spec/grape/exceptions/base_spec.rb +0 -81
- data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
- data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_option_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
- data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
- data/spec/grape/exceptions/validation_spec.rb +0 -19
- data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
- data/spec/grape/grape_spec.rb +0 -9
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
- data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
- data/spec/grape/integration/rack_spec.rb +0 -51
- data/spec/grape/loading_spec.rb +0 -44
- data/spec/grape/middleware/auth/base_spec.rb +0 -31
- data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
- data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
- data/spec/grape/middleware/base_spec.rb +0 -221
- data/spec/grape/middleware/error_spec.rb +0 -85
- data/spec/grape/middleware/exception_spec.rb +0 -294
- data/spec/grape/middleware/formatter_spec.rb +0 -461
- data/spec/grape/middleware/globals_spec.rb +0 -30
- data/spec/grape/middleware/stack_spec.rb +0 -155
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
- data/spec/grape/middleware/versioner/header_spec.rb +0 -345
- data/spec/grape/middleware/versioner/param_spec.rb +0 -171
- data/spec/grape/middleware/versioner/path_spec.rb +0 -62
- data/spec/grape/middleware/versioner_spec.rb +0 -21
- data/spec/grape/named_api_spec.rb +0 -19
- data/spec/grape/parser_spec.rb +0 -86
- data/spec/grape/path_spec.rb +0 -252
- data/spec/grape/presenters/presenter_spec.rb +0 -71
- data/spec/grape/request_spec.rb +0 -126
- data/spec/grape/util/inheritable_setting_spec.rb +0 -242
- data/spec/grape/util/inheritable_values_spec.rb +0 -79
- data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
- data/spec/grape/util/stackable_values_spec.rb +0 -128
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
- data/spec/grape/validations/attributes_doc_spec.rb +0 -153
- data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
- data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
- data/spec/grape/validations/types_spec.rb +0 -111
- data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
- data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
- data/spec/grape/validations/validators/base_spec.rb +0 -38
- data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
- data/spec/grape/validations/validators/default_spec.rb +0 -463
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
- data/spec/grape/validations/validators/except_values_spec.rb +0 -192
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
- data/spec/grape/validations/validators/presence_spec.rb +0 -315
- data/spec/grape/validations/validators/regexp_spec.rb +0 -161
- data/spec/grape/validations/validators/same_as_spec.rb +0 -57
- data/spec/grape/validations/validators/values_spec.rb +0 -733
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2030
- data/spec/integration/eager_load/eager_load_spec.rb +0 -15
- data/spec/integration/multi_json/json_spec.rb +0 -7
- data/spec/integration/multi_xml/xml_spec.rb +0 -7
- data/spec/shared/deprecated_class_examples.rb +0 -16
- data/spec/shared/versioning_examples.rb +0 -215
- data/spec/spec_helper.rb +0 -52
- data/spec/support/basic_auth_encode_helpers.rb +0 -11
- data/spec/support/chunks.rb +0 -14
- data/spec/support/content_type_helpers.rb +0 -15
- data/spec/support/endpoint_faker.rb +0 -25
- data/spec/support/file_streamer.rb +0 -13
- data/spec/support/integer_helpers.rb +0 -13
- data/spec/support/versioned_helpers.rb +0 -55
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/dsl/headers'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module Middleware
|
|
7
5
|
class Base
|
|
8
|
-
include Helpers
|
|
9
|
-
|
|
10
|
-
attr_reader :app, :env, :options
|
|
11
|
-
|
|
12
|
-
TEXT_HTML = 'text/html'
|
|
13
|
-
|
|
14
6
|
include Grape::DSL::Headers
|
|
15
7
|
|
|
8
|
+
attr_reader :app, :env, :options, :config
|
|
9
|
+
|
|
16
10
|
# @param [Rack Application] app The standard argument for a Rack middleware.
|
|
17
|
-
# @param [Hash] options
|
|
18
|
-
|
|
11
|
+
# @param [Hash] options Options forwarded to the subclass. When the
|
|
12
|
+
# subclass declares an `Options` Data class, the kwargs are routed
|
|
13
|
+
# through it and exposed via {#config}; {#options} keeps returning a
|
|
14
|
+
# frozen Hash representation for back-compat with subclasses that read
|
|
15
|
+
# `options[:key]`. Otherwise the kwargs are deep-merged with the
|
|
16
|
+
# subclass's `DEFAULT_OPTIONS` Hash (legacy path) and frozen.
|
|
17
|
+
def initialize(app, **options)
|
|
19
18
|
@app = app
|
|
20
|
-
|
|
19
|
+
if (config_class = options_data_class)
|
|
20
|
+
@config = config_class.new(**options)
|
|
21
|
+
@options = @config.to_h.freeze
|
|
22
|
+
else
|
|
23
|
+
@options = merge_default_options(options).freeze
|
|
24
|
+
end
|
|
21
25
|
@app_response = nil
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
def default_options
|
|
25
|
-
{}
|
|
26
|
-
end
|
|
27
|
-
|
|
28
28
|
def call(env)
|
|
29
29
|
dup.call!(env).to_a
|
|
30
30
|
end
|
|
@@ -57,40 +57,63 @@ module Grape
|
|
|
57
57
|
# @return [Response, nil] a Rack SPEC response or nil to call the application afterwards.
|
|
58
58
|
def after; end
|
|
59
59
|
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@app_response = Rack::Response.new(@app_response[2], @app_response[0], @app_response[1])
|
|
60
|
+
def rack_request
|
|
61
|
+
@rack_request ||= Rack::Request.new(env)
|
|
64
62
|
end
|
|
65
63
|
|
|
66
|
-
def
|
|
67
|
-
|
|
64
|
+
def context
|
|
65
|
+
env[Grape::Env::API_ENDPOINT]
|
|
68
66
|
end
|
|
69
67
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
end
|
|
68
|
+
def response
|
|
69
|
+
return @app_response if @app_response.is_a?(Rack::Response)
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) || TEXT_HTML
|
|
71
|
+
@app_response = Rack::Response[*@app_response]
|
|
76
72
|
end
|
|
77
73
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
def query_params
|
|
75
|
+
rack_request.GET
|
|
76
|
+
rescue *Grape::RACK_ERRORS
|
|
77
|
+
raise Grape::Exceptions::RequestError
|
|
82
78
|
end
|
|
83
79
|
|
|
84
80
|
private
|
|
85
81
|
|
|
86
82
|
def merge_headers(response)
|
|
87
|
-
return
|
|
83
|
+
return if @header.blank?
|
|
88
84
|
|
|
89
85
|
case response
|
|
90
|
-
when Rack::Response then response.headers.merge!(
|
|
91
|
-
when Array then response[1].merge!(
|
|
86
|
+
when Rack::Response then response.headers.merge!(@header)
|
|
87
|
+
when Array then response[1].merge!(@header)
|
|
92
88
|
end
|
|
93
89
|
end
|
|
90
|
+
|
|
91
|
+
def merge_default_options(options)
|
|
92
|
+
return default_options.deep_merge(options) if respond_to?(:default_options)
|
|
93
|
+
|
|
94
|
+
default_options_constant&.deep_merge(options) || options
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# self.class::Options honours middleware inheritance (e.g. Versioner::Path
|
|
98
|
+
# → Versioner::Base) and, unlike const_defined?, never resolves a
|
|
99
|
+
# top-level ::Options on Object. Absent an own/inherited Options class,
|
|
100
|
+
# the lookup raises NameError and we fall back to the legacy path.
|
|
101
|
+
def options_data_class
|
|
102
|
+
self.class::Options
|
|
103
|
+
rescue NameError
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Same idea as {#options_data_class} for the legacy DEFAULT_OPTIONS Hash.
|
|
108
|
+
def default_options_constant
|
|
109
|
+
self.class::DEFAULT_OPTIONS
|
|
110
|
+
rescue NameError
|
|
111
|
+
nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def try_scrub(obj)
|
|
115
|
+
obj.respond_to?(:valid_encoding?) && !obj.valid_encoding? ? obj.scrub : obj
|
|
116
|
+
end
|
|
94
117
|
end
|
|
95
118
|
end
|
|
96
119
|
end
|
|
@@ -1,138 +1,337 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/middleware/base'
|
|
4
|
-
require 'active_support/core_ext/string/output_safety'
|
|
5
|
-
|
|
6
3
|
module Grape
|
|
7
4
|
module Middleware
|
|
8
5
|
class Error < Base
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
6
|
+
extend Forwardable
|
|
7
|
+
include PrecomputedContentTypes
|
|
8
|
+
|
|
9
|
+
Options = Data.define(
|
|
10
|
+
:all_rescue_handler, :base_only_rescue_handlers, :content_types,
|
|
11
|
+
:default_error_formatter, :default_message, :default_status,
|
|
12
|
+
:error_formatters, :format,
|
|
13
|
+
:grape_exceptions_rescue_handler, :internal_grape_exceptions_rescue_handler,
|
|
14
|
+
:rescue_all, :rescue_grape_exceptions, :rescue_handlers, :rescue_options
|
|
15
|
+
) do
|
|
16
|
+
def initialize(
|
|
17
|
+
all_rescue_handler: nil, base_only_rescue_handlers: nil, content_types: nil,
|
|
18
|
+
default_error_formatter: nil, default_message: '', default_status: 500,
|
|
19
|
+
error_formatters: nil, format: :txt,
|
|
20
|
+
grape_exceptions_rescue_handler: nil, internal_grape_exceptions_rescue_handler: nil,
|
|
21
|
+
rescue_all: false, rescue_grape_exceptions: false, rescue_handlers: nil,
|
|
22
|
+
rescue_options: nil
|
|
23
|
+
)
|
|
24
|
+
# `rescue_options:` and `default_error_formatter:` arrive nil from
|
|
25
|
+
# `Endpoint#error_middleware_options` when the API called no
|
|
26
|
+
# `rescue_from` and no `format` — and an explicit nil bypasses the
|
|
27
|
+
# keyword defaults above, so restore them here rather than letting nil
|
|
28
|
+
# propagate to `def_delegator :rescue_options, :backtrace` or to the
|
|
29
|
+
# formatter lookup in `#format_message`.
|
|
30
|
+
super(
|
|
31
|
+
rescue_options: rescue_options || Grape::DSL::RescueOptions.new,
|
|
32
|
+
default_error_formatter: default_error_formatter || Grape::ErrorFormatter::Txt,
|
|
33
|
+
all_rescue_handler:, base_only_rescue_handlers:, content_types:,
|
|
34
|
+
default_message:, default_status:, error_formatters:, format:,
|
|
35
|
+
grape_exceptions_rescue_handler:, internal_grape_exceptions_rescue_handler:,
|
|
36
|
+
rescue_all:, rescue_grape_exceptions:, rescue_handlers:
|
|
37
|
+
)
|
|
38
|
+
end
|
|
33
39
|
end
|
|
34
40
|
|
|
41
|
+
def_delegators :config,
|
|
42
|
+
:all_rescue_handler, :base_only_rescue_handlers, :default_error_formatter,
|
|
43
|
+
:default_message, :default_status, :error_formatters, :format,
|
|
44
|
+
:grape_exceptions_rescue_handler, :internal_grape_exceptions_rescue_handler,
|
|
45
|
+
:rescue_all, :rescue_grape_exceptions, :rescue_handlers, :rescue_options
|
|
46
|
+
|
|
47
|
+
# +:backtrace+ / +:original_exception+ on the rescue options become
|
|
48
|
+
# +#include_backtrace+ / +#include_original_exception+ on the middleware,
|
|
49
|
+
# which is what the formatter call site reads.
|
|
50
|
+
def_delegator :rescue_options, :backtrace, :include_backtrace
|
|
51
|
+
def_delegator :rescue_options, :original_exception, :include_original_exception
|
|
52
|
+
|
|
53
|
+
# Emitted by {#render_failsafe_response} once even the framework's own message
|
|
54
|
+
# could not be rendered. Deliberately built without a formatter, an i18n
|
|
55
|
+
# lookup or anything else that could be the thing that is broken.
|
|
56
|
+
FAILSAFE_STATUS = 500
|
|
57
|
+
FAILSAFE_MESSAGE = '500 Internal Server Error'
|
|
58
|
+
FAILSAFE_CONTENT_TYPE = 'text/plain'
|
|
59
|
+
|
|
35
60
|
def call!(env)
|
|
36
61
|
@env = env
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
end)
|
|
41
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
42
|
-
handler =
|
|
43
|
-
rescue_handler_for_base_only_class(e.class) ||
|
|
44
|
-
rescue_handler_for_class_or_its_ancestor(e.class) ||
|
|
45
|
-
rescue_handler_for_grape_exception(e.class) ||
|
|
46
|
-
rescue_handler_for_any_class(e.class) ||
|
|
47
|
-
raise
|
|
48
|
-
|
|
49
|
-
run_rescue_handler(handler, e)
|
|
50
|
-
end
|
|
62
|
+
error_response(catch(:error) { return @app.call(@env) })
|
|
63
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
64
|
+
run_rescue_handler(find_handler(e.class), e, @env[Grape::Env::API_ENDPOINT])
|
|
51
65
|
end
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def rack_response(status, headers, message)
|
|
70
|
+
body = html_content_type?(headers[Rack::CONTENT_TYPE]) ? Rack::Utils.escape_html(message) : message
|
|
71
|
+
Rack::Response.new(Array.wrap(body), Rack::Utils.status_code(status), Grape::Util::Header.new.merge!(headers))
|
|
56
72
|
end
|
|
57
73
|
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
# Escaping must key off the media type only, case-insensitively. Comparing
|
|
75
|
+
# the raw header against 'text/html' would let a parameterized value such
|
|
76
|
+
# as 'text/html; charset=utf-8' (or a differently-cased 'Text/HTML', which
|
|
77
|
+
# browsers still treat as HTML) skip escaping and reflect an unescaped
|
|
78
|
+
# message into an HTML response. Such a header can be set from several
|
|
79
|
+
# places (a registered content type, or a custom Content-Type passed to
|
|
80
|
+
# error!/rescue_from), but they all render here.
|
|
81
|
+
def html_content_type?(content_type)
|
|
82
|
+
Grape::ContentTypes.media_type(content_type).to_s.casecmp?('text/html')
|
|
60
83
|
end
|
|
61
84
|
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
85
|
+
# The registry answers nil for a format nothing is registered for, and
|
|
86
|
+
# the API's +default_error_formatter+ — +ErrorFormatter::Txt+ unless the
|
|
87
|
+
# API set another — takes it from there, so this always has something
|
|
88
|
+
# callable. The +throw :error, 406+ that used to stand in for a missing
|
|
89
|
+
# formatter could not work anyway: nothing catches +:error+ around this
|
|
90
|
+
# call (+#call!+ has left its +catch+ by the time +error_response+ runs),
|
|
91
|
+
# so it raised +UncaughtThrowError+ and the request answered with the
|
|
92
|
+
# failsafe 500 rather than the 406 it named.
|
|
93
|
+
def format_message(error)
|
|
94
|
+
current_format = env[Grape::Env::API_FORMAT] || format
|
|
95
|
+
formatter = Grape::ErrorFormatter.formatter_for(current_format, error_formatters) || default_error_formatter
|
|
96
|
+
formatter.call(error:, env:, include_backtrace:, include_original_exception:)
|
|
71
97
|
end
|
|
72
98
|
|
|
73
|
-
def
|
|
74
|
-
|
|
75
|
-
|
|
99
|
+
def find_handler(klass)
|
|
100
|
+
registered_entry = registered_rescue_handler_entry(klass)
|
|
101
|
+
|
|
102
|
+
grape_exceptions_precedence_handler(klass, registered_entry) ||
|
|
103
|
+
registered_entry&.last ||
|
|
104
|
+
rescue_handler_for_grape_exception(klass) ||
|
|
105
|
+
rescue_handler_for_any_class(klass) ||
|
|
106
|
+
raise
|
|
76
107
|
end
|
|
77
108
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
def error_response(error = nil)
|
|
110
|
+
raw = Grape::Exceptions::ErrorResponse.coerce(error)
|
|
111
|
+
headers = { Rack::CONTENT_TYPE => content_type }
|
|
112
|
+
headers.merge!(raw.headers) if raw.headers.is_a?(Hash)
|
|
113
|
+
payload = raw.with(
|
|
114
|
+
status: raw.status || default_status,
|
|
115
|
+
message: raw.message || default_message,
|
|
116
|
+
headers:,
|
|
117
|
+
backtrace: resolved_backtrace(raw)
|
|
118
|
+
)
|
|
119
|
+
env[Grape::Env::API_ENDPOINT].status(payload.status) # error! may not have been called
|
|
120
|
+
render_response(payload)
|
|
87
121
|
end
|
|
88
122
|
|
|
89
|
-
|
|
123
|
+
# The backtrace an error formatter is handed. Assembled only when the API
|
|
124
|
+
# asked for one with `rescue_from ..., backtrace: true`: reading it off
|
|
125
|
+
# the exception is not free — +Exception#backtrace+ builds the whole Array
|
|
126
|
+
# of location strings — and every built-in formatter drops it otherwise.
|
|
127
|
+
# A formatter that wants one regardless still has +original_exception+.
|
|
128
|
+
def resolved_backtrace(raw)
|
|
129
|
+
return [] unless include_backtrace
|
|
130
|
+
|
|
131
|
+
raw.backtrace || raw.original_exception&.backtrace || []
|
|
132
|
+
end
|
|
90
133
|
|
|
91
|
-
|
|
92
|
-
|
|
134
|
+
# Rendering runs inside #call!'s own rescue clause, so it is not covered by
|
|
135
|
+
# that rescue: an error formatter that raises on the payload it was handed
|
|
136
|
+
# takes the exception out through every middleware above Grape. By this
|
|
137
|
+
# point Grape has committed to answering with an error, so it answers with
|
|
138
|
+
# one that does not depend on the payload rather than dropping the request.
|
|
139
|
+
#
|
|
140
|
+
# +Grape.config.raise_rendering_errors+ opts back out, for an application
|
|
141
|
+
# that would rather have the exception propagate as it did before.
|
|
142
|
+
def render_response(payload)
|
|
143
|
+
rack_response(payload.status, payload.headers, format_message(payload))
|
|
144
|
+
rescue StandardError => e
|
|
145
|
+
raise if Grape.config.raise_rendering_errors
|
|
93
146
|
|
|
94
|
-
|
|
147
|
+
record_rendering_failure(e)
|
|
148
|
+
render_failsafe_response
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# The exception is published on the rack env (see {#expose_exception}) and
|
|
152
|
+
# written to +rack.errors+ so it reaches the log with no tracker installed.
|
|
153
|
+
# Rails writes to $stderr from its failsafe branch for the same reason:
|
|
154
|
+
# deferring the logging to the application is not an option when the
|
|
155
|
+
# application's own error rendering is what broke.
|
|
156
|
+
def record_rendering_failure(error)
|
|
157
|
+
expose_exception(error)
|
|
158
|
+
env[Rack::RACK_ERRORS]&.write("Grape could not render the error response: #{error.class}: #{error.message}\n")
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# First retry the API's own format with the framework's InternalServerError,
|
|
162
|
+
# whose message is a static string and so cannot be what defeated the first
|
|
163
|
+
# attempt. Should even that fail — a wholesale broken formatter, rather than
|
|
164
|
+
# one payload it choked on — drop the formatter entirely. Both attempts call
|
|
165
|
+
# {#format_message} directly rather than re-entering {#error_response}, so
|
|
166
|
+
# this path cannot recurse.
|
|
167
|
+
def render_failsafe_response
|
|
168
|
+
headers = { Rack::CONTENT_TYPE => content_type }
|
|
169
|
+
rack_response(FAILSAFE_STATUS, headers, format_message(failsafe_payload(headers)))
|
|
170
|
+
rescue StandardError
|
|
171
|
+
rack_response(FAILSAFE_STATUS, { Rack::CONTENT_TYPE => FAILSAFE_CONTENT_TYPE }, FAILSAFE_MESSAGE)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Publish an exception Grape swallowed, on both keys. +grape.exception+ is
|
|
175
|
+
# Grape's own and has been set on these paths all along; +rack.exception+ is
|
|
176
|
+
# what the ecosystem actually reads to find an exception that never
|
|
177
|
+
# propagated — sentry-ruby collects +env['rack.exception'] ||
|
|
178
|
+
# env['sinatra.error']+ — so a tracker mounted above Grape keeps reporting
|
|
179
|
+
# these with no application change.
|
|
180
|
+
def expose_exception(error)
|
|
181
|
+
env[Grape::Env::GRAPE_EXCEPTION] = error
|
|
182
|
+
env[Grape::Env::RACK_EXCEPTION] = error
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def failsafe_payload(headers)
|
|
186
|
+
Grape::Exceptions::ErrorResponse.new(
|
|
187
|
+
status: FAILSAFE_STATUS,
|
|
188
|
+
message: Grape::Exceptions::InternalServerError.new.message,
|
|
189
|
+
headers:,
|
|
190
|
+
backtrace: [],
|
|
191
|
+
original_exception: nil
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def default_rescue_handler(exception)
|
|
196
|
+
error_response(
|
|
197
|
+
Grape::Exceptions::ErrorResponse.new(
|
|
198
|
+
message: exception.message,
|
|
199
|
+
backtrace: exception.backtrace,
|
|
200
|
+
original_exception: exception
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def registered_rescue_handler(klass)
|
|
206
|
+
registered_rescue_handler_entry(klass)&.last
|
|
207
|
+
end
|
|
95
208
|
|
|
96
|
-
|
|
209
|
+
# The matched entry rather than just its handler, so callers can tell
|
|
210
|
+
# *which* class matched — see {#grape_exceptions_precedence_handler}.
|
|
211
|
+
# @return [Array(Class, #call), nil]
|
|
212
|
+
def registered_rescue_handler_entry(klass)
|
|
213
|
+
rescue_handler_entry_from(base_only_rescue_handlers) { |err| klass == err } ||
|
|
214
|
+
rescue_handler_entry_from(rescue_handlers) { |err| klass <= err }
|
|
97
215
|
end
|
|
98
216
|
|
|
99
|
-
def
|
|
100
|
-
error, handler =
|
|
217
|
+
def rescue_handler_entry_from(handlers)
|
|
218
|
+
error, handler = handlers&.find { |err, _handler| yield(err) }
|
|
101
219
|
|
|
102
220
|
return unless error
|
|
103
221
|
|
|
104
|
-
handler || :default_rescue_handler
|
|
222
|
+
[error, handler || method(:default_rescue_handler)]
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# +rescue_from :grape_exceptions+ is an opt-in to keep Grape's own errors
|
|
226
|
+
# rendering with their own status — a validation failure stays a 400
|
|
227
|
+
# instead of becoming whatever the app's catch-all returns.
|
|
228
|
+
#
|
|
229
|
+
# It only ever worked against +rescue_from :all+, which lives in
|
|
230
|
+
# +all_rescue_handler+ and is consulted last. Spelled as a class instead,
|
|
231
|
+
# +rescue_from StandardError+ is a *registered* handler, matched first,
|
|
232
|
+
# and Grape's exceptions are StandardErrors — so the opt-in silently did
|
|
233
|
+
# nothing and validation errors came back as 500s either way.
|
|
234
|
+
#
|
|
235
|
+
# Let it win over a handler that only matched through a non-Grape
|
|
236
|
+
# ancestor. One registered for a Grape exception class is more specific
|
|
237
|
+
# than the opt-in and still wins, so an explicit
|
|
238
|
+
# +rescue_from Grape::Exceptions::ValidationErrors+ keeps its handler.
|
|
239
|
+
#
|
|
240
|
+
# InvalidVersionHeader is left alone: it must keep reaching Rack so the
|
|
241
|
+
# next versioned route is tried.
|
|
242
|
+
def grape_exceptions_precedence_handler(klass, registered_entry)
|
|
243
|
+
return unless rescue_grape_exceptions
|
|
244
|
+
return unless klass <= Grape::Exceptions::Base
|
|
245
|
+
return if klass == Grape::Exceptions::InvalidVersionHeader
|
|
246
|
+
|
|
247
|
+
matched, = registered_entry
|
|
248
|
+
return if matched.nil? || matched <= Grape::Exceptions::Base
|
|
249
|
+
|
|
250
|
+
grape_exceptions_rescue_handler || method(:error_response)
|
|
105
251
|
end
|
|
106
252
|
|
|
107
253
|
def rescue_handler_for_grape_exception(klass)
|
|
108
254
|
return unless klass <= Grape::Exceptions::Base
|
|
109
|
-
return :error_response if klass == Grape::Exceptions::InvalidVersionHeader
|
|
110
|
-
return unless
|
|
255
|
+
return method(:error_response) if klass == Grape::Exceptions::InvalidVersionHeader
|
|
256
|
+
return unless rescue_grape_exceptions || !rescue_all
|
|
111
257
|
|
|
112
|
-
|
|
258
|
+
grape_exceptions_rescue_handler || method(:error_response)
|
|
113
259
|
end
|
|
114
260
|
|
|
115
261
|
def rescue_handler_for_any_class(klass)
|
|
116
262
|
return unless klass <= StandardError
|
|
117
|
-
return unless
|
|
263
|
+
return unless rescue_all || rescue_grape_exceptions
|
|
118
264
|
|
|
119
|
-
|
|
265
|
+
all_rescue_handler || method(:default_rescue_handler)
|
|
120
266
|
end
|
|
121
267
|
|
|
122
|
-
def run_rescue_handler(handler, error)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
268
|
+
def run_rescue_handler(handler, error, endpoint, redispatched: false)
|
|
269
|
+
callable = handler.is_a?(Symbol) ? endpoint.public_method(handler) : handler
|
|
270
|
+
response = catch(:error) do
|
|
271
|
+
callable.arity.zero? ? endpoint.instance_exec(&callable) : endpoint.instance_exec(error, &callable)
|
|
272
|
+
rescue StandardError => e
|
|
273
|
+
return redispatch(e, endpoint, redispatched)
|
|
127
274
|
end
|
|
128
275
|
|
|
129
|
-
|
|
276
|
+
return error_response(response) if error?(response)
|
|
277
|
+
return response if response.is_a?(Rack::Response)
|
|
130
278
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
279
|
+
run_rescue_handler(method(:default_rescue_handler), Grape::Exceptions::InvalidResponse.new, endpoint)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Route an exception raised inside a +rescue_from+ block.
|
|
283
|
+
#
|
|
284
|
+
# * If we have already redispatched once (the redispatched handler
|
|
285
|
+
# itself raised), go straight to {#framework_default} — bounds the
|
|
286
|
+
# chain at one redispatch.
|
|
287
|
+
# * Else if the exception has a registered +rescue_from+ handler,
|
|
288
|
+
# run it.
|
|
289
|
+
# * Else if it's a +Grape::Exceptions::Base+ subclass, render it
|
|
290
|
+
# through +error_response+ with its own +status+ and +message+.
|
|
291
|
+
# * Else fall through to {#safe_default}, which lets the user opt
|
|
292
|
+
# in via +rescue_from :internal_grape_exceptions+ or, failing
|
|
293
|
+
# that, applies the framework default.
|
|
294
|
+
def redispatch(error, endpoint, already_redispatched)
|
|
295
|
+
return framework_default(endpoint) if already_redispatched
|
|
296
|
+
|
|
297
|
+
registered = registered_rescue_handler(error.class)
|
|
298
|
+
|
|
299
|
+
return run_rescue_handler(registered, error, endpoint, redispatched: true) if registered
|
|
300
|
+
return run_rescue_handler(method(:error_response), error, endpoint, redispatched: true) if error.is_a?(Grape::Exceptions::Base)
|
|
301
|
+
|
|
302
|
+
safe_default(error, endpoint)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# The unrecognised-error path. Exposes the original exception on
|
|
306
|
+
# the rack env so upstream Rack middleware (loggers, error
|
|
307
|
+
# trackers) can observe it. If the user registered a
|
|
308
|
+
# +rescue_from :internal_grape_exceptions+ handler, that handler
|
|
309
|
+
# runs and owns the response. Otherwise the framework renders the
|
|
310
|
+
# generic +InternalServerError+ — never the original exception's
|
|
311
|
+
# message. The framework deliberately does no logging of its own
|
|
312
|
+
# here; that's the application's call.
|
|
313
|
+
def safe_default(error, endpoint)
|
|
314
|
+
expose_exception(error)
|
|
315
|
+
return run_rescue_handler(internal_grape_exceptions_rescue_handler, error, endpoint, redispatched: true) if internal_grape_exceptions_rescue_handler
|
|
316
|
+
|
|
317
|
+
framework_default(endpoint)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def framework_default(endpoint)
|
|
321
|
+
run_rescue_handler(method(:default_rescue_handler), Grape::Exceptions::InternalServerError.new, endpoint)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def error!(message, status = default_status, headers = {}, backtrace = [], original_exception = nil)
|
|
325
|
+
env[Grape::Env::API_ENDPOINT].status(status) # not error! inside route
|
|
326
|
+
merged_headers = { Rack::CONTENT_TYPE => content_type }.merge!(headers)
|
|
327
|
+
error = Grape::Exceptions::ErrorResponse.new(
|
|
328
|
+
status:, message:, headers: merged_headers, backtrace:, original_exception:
|
|
329
|
+
)
|
|
330
|
+
rack_response(status, merged_headers, format_message(error))
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def error?(response)
|
|
334
|
+
response.is_a?(Grape::Exceptions::ErrorResponse)
|
|
136
335
|
end
|
|
137
336
|
end
|
|
138
337
|
end
|