grape 1.8.0 → 3.3.5
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 +391 -1
- data/CONTRIBUTING.md +3 -11
- data/README.md +648 -552
- data/UPGRADING.md +803 -7
- data/grape.gemspec +11 -14
- data/lib/grape/api/instance.rb +68 -158
- data/lib/grape/api.rb +71 -107
- data/lib/grape/content_types.rb +23 -11
- 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 +14 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +15 -63
- data/lib/grape/dsl/entity.rb +88 -0
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +83 -64
- data/lib/grape/dsl/inside_route.rb +56 -295
- data/lib/grape/dsl/logger.rb +4 -9
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +50 -82
- data/lib/grape/dsl/request_response.rb +144 -146
- data/lib/grape/dsl/rescue_options.rb +24 -0
- data/lib/grape/dsl/routing.rb +261 -186
- 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 +19 -0
- data/lib/grape/endpoint.rb +277 -250
- data/lib/grape/{util/env.rb → env.rb} +1 -8
- data/lib/grape/error_formatter/base.rb +56 -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 +5 -25
- data/lib/grape/exceptions/base.rb +22 -58
- data/lib/grape/exceptions/error_response.rb +45 -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_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 +25 -9
- 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 +4 -6
- data/lib/grape/formatter/serializable_hash.rb +6 -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 +43 -42
- data/lib/grape/middleware/auth/base.rb +11 -33
- data/lib/grape/middleware/auth/dsl.rb +37 -31
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/base.rb +56 -33
- data/lib/grape/middleware/deprecated_options_hash_access.rb +19 -0
- data/lib/grape/middleware/error.rb +183 -91
- data/lib/grape/middleware/formatter.rb +94 -105
- data/lib/grape/middleware/precomputed_content_types.rb +46 -0
- data/lib/grape/middleware/stack.rb +27 -38
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +72 -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 +13 -32
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/mountable.rb +22 -0
- data/lib/grape/namespace.rb +18 -12
- 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 +38 -63
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +168 -26
- data/lib/grape/router/base_route.rb +48 -0
- data/lib/grape/router/greedy_route.rb +26 -0
- data/lib/grape/router/mustermann_pattern.rb +44 -0
- data/lib/grape/router/pattern.rb +30 -34
- data/lib/grape/router/route.rb +28 -61
- data/lib/grape/router.rb +71 -86
- data/lib/grape/serve_stream/file_body.rb +1 -0
- data/lib/grape/serve_stream/sendfile_response.rb +3 -5
- data/lib/grape/serve_stream/stream_response.rb +1 -0
- data/lib/grape/testing.rb +33 -0
- data/lib/grape/util/api_description.rb +58 -0
- data/lib/grape/util/base_inheritable.rb +14 -14
- data/lib/grape/util/cache.rb +1 -3
- data/lib/grape/util/deep_freeze.rb +35 -0
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +51 -27
- data/lib/grape/util/inheritable_values.rb +7 -5
- 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 +67 -0
- data/lib/grape/util/path_normalizer.rb +34 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +12 -14
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +43 -27
- data/lib/grape/validations/coerce_options.rb +21 -0
- data/lib/grape/validations/contract_scope.rb +28 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/oneof_collector.rb +39 -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 +180 -303
- data/lib/grape/validations/shared_options.rb +19 -0
- data/lib/grape/validations/single_attribute_iterator.rb +2 -2
- data/lib/grape/validations/types/array_coercer.rb +4 -7
- data/lib/grape/validations/types/custom_type_coercer.rb +41 -85
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +15 -28
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +11 -35
- data/lib/grape/validations/types/set_coercer.rb +1 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +11 -0
- 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 +120 -36
- data/lib/grape/validations/validators/coerce_validator.rb +18 -36
- data/lib/grape/validations/validators/contract_scope_validator.rb +45 -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 +48 -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 +49 -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 +6 -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 +75 -288
- metadata +79 -291
- 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/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/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
data/lib/grape/endpoint.rb
CHANGED
|
@@ -6,65 +6,40 @@ module Grape
|
|
|
6
6
|
# on the instance level of this class may be called
|
|
7
7
|
# from inside a `get`, `post`, etc.
|
|
8
8
|
class Endpoint
|
|
9
|
+
extend Forwardable
|
|
9
10
|
include Grape::DSL::Settings
|
|
11
|
+
include Grape::DSL::Headers
|
|
10
12
|
include Grape::DSL::InsideRoute
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
attr_reader :env, :request, :source, :options, :endpoints
|
|
15
|
+
attr_accessor :options_route_enabled
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
self == Endpoint ? Class.new(Endpoint).new(*args, &block) : super
|
|
18
|
-
end
|
|
17
|
+
def_delegators :request, :params, :headers, :cookies
|
|
18
|
+
def_delegator :cookies, :response_cookies
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
else
|
|
27
|
-
@before_each = [new_setup]
|
|
28
|
-
end
|
|
29
|
-
end
|
|
20
|
+
# The logger configured on the API this endpoint belongs to. Available
|
|
21
|
+
# inside route handlers, +before+/+after+/+after_validation+/+finally+
|
|
22
|
+
# filters, and +rescue_from+ blocks.
|
|
23
|
+
def logger
|
|
24
|
+
config.for.logger
|
|
25
|
+
end
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
end
|
|
27
|
+
class << self
|
|
28
|
+
def block_to_unbound_method(block)
|
|
29
|
+
return unless block
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
# The unbound method allows explicit calls to +return+ without raising a
|
|
42
|
-
# +LocalJumpError+. The method will be removed, but a +Proc+ reference to
|
|
43
|
-
# it will be returned. The returned +Proc+ expects a single argument: the
|
|
44
|
-
# instance of +Endpoint+ to bind to the method during the call.
|
|
45
|
-
#
|
|
46
|
-
# @param [String, Symbol] method_name
|
|
47
|
-
# @return [Proc]
|
|
48
|
-
# @raise [NameError] an instance method with the same name already exists
|
|
49
|
-
def generate_api_method(method_name, &block)
|
|
50
|
-
raise NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name") if method_defined?(method_name)
|
|
51
|
-
|
|
52
|
-
define_method(method_name, &block)
|
|
53
|
-
method = instance_method(method_name)
|
|
54
|
-
remove_method(method_name)
|
|
55
|
-
|
|
56
|
-
proc do |endpoint_instance|
|
|
57
|
-
ActiveSupport::Notifications.instrument('endpoint_render.grape', endpoint: endpoint_instance) do
|
|
58
|
-
method.bind(endpoint_instance).call
|
|
59
|
-
end
|
|
60
|
-
end
|
|
31
|
+
define_method :temp_unbound_method, block
|
|
32
|
+
method = instance_method(:temp_unbound_method)
|
|
33
|
+
remove_method :temp_unbound_method
|
|
34
|
+
method
|
|
61
35
|
end
|
|
62
36
|
end
|
|
63
37
|
|
|
64
38
|
# Create a new endpoint.
|
|
65
39
|
# @param new_settings [InheritableSetting] settings to determine the params,
|
|
66
40
|
# validations, and other properties from.
|
|
67
|
-
# @param options [Hash] attributes of this endpoint
|
|
41
|
+
# @param options [Hash] attributes of this endpoint, normalized into a
|
|
42
|
+
# +Grape::Endpoint::Options+ value object.
|
|
68
43
|
# @option options path [String or Array] the path to this endpoint, within
|
|
69
44
|
# the current scope.
|
|
70
45
|
# @option options method [String or Array] which HTTP method(s) can be used
|
|
@@ -73,69 +48,46 @@ module Grape
|
|
|
73
48
|
# @note This happens at the time of API definition, so in this context the
|
|
74
49
|
# endpoint does not know if it will be mounted under a different endpoint.
|
|
75
50
|
# @yield a block defining what your API should do when this endpoint is hit
|
|
76
|
-
def initialize(new_settings, options
|
|
77
|
-
require_option(options, :path)
|
|
78
|
-
require_option(options, :method)
|
|
79
|
-
|
|
51
|
+
def initialize(new_settings, **options, &block)
|
|
80
52
|
self.inheritable_setting = new_settings.point_in_time_copy
|
|
81
53
|
|
|
82
54
|
# now +namespace_stackable(:declared_params)+ contains all params defined for
|
|
83
55
|
# this endpoint and its parents, but later it will be cleaned up,
|
|
84
56
|
# see +reset_validations!+ in lib/grape/dsl/validations.rb
|
|
85
|
-
|
|
86
|
-
|
|
57
|
+
inheritable_setting.route[:declared_params] = inheritable_setting.namespace_stackable[:declared_params].flatten
|
|
58
|
+
inheritable_setting.route[:saved_validations] = inheritable_setting.namespace_stackable[:validations].dup
|
|
87
59
|
|
|
88
|
-
namespace_stackable
|
|
89
|
-
namespace_inheritable
|
|
60
|
+
inheritable_setting.namespace_stackable[:representations] ||= []
|
|
61
|
+
inheritable_setting.namespace_inheritable[:default_error_status] ||= 500
|
|
90
62
|
|
|
91
63
|
@options = options
|
|
92
|
-
|
|
93
|
-
@options[:path]
|
|
94
|
-
@options[:
|
|
95
|
-
|
|
96
|
-
@options[:method] = Array(options[:method])
|
|
97
|
-
@options[:route_options] ||= {}
|
|
98
|
-
|
|
99
|
-
@lazy_initialize_lock = Mutex.new
|
|
100
|
-
@lazy_initialized = nil
|
|
101
|
-
@block = nil
|
|
64
|
+
@options[:path] = Array(@options[:path])
|
|
65
|
+
@options[:path] << '/' if @options[:path].empty?
|
|
66
|
+
@options[:method] = Array(@options[:method])
|
|
67
|
+
@config = Options.new(**options)
|
|
102
68
|
|
|
103
69
|
@status = nil
|
|
104
70
|
@stream = nil
|
|
105
71
|
@body = nil
|
|
106
|
-
@
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@source = block
|
|
111
|
-
@block = self.class.generate_api_method(method_name, &block)
|
|
72
|
+
@source = self.class.block_to_unbound_method(block)
|
|
73
|
+
@before_filter_passed = false
|
|
74
|
+
@options_route_enabled = false
|
|
75
|
+
@endpoints = @config.app.endpoints if @config.app.respond_to?(:endpoints)
|
|
112
76
|
end
|
|
113
77
|
|
|
114
78
|
# Update our settings from a given set of stackable parameters. Used when
|
|
115
79
|
# the endpoint's API is mounted under another one.
|
|
116
80
|
def inherit_settings(namespace_stackable)
|
|
117
|
-
|
|
81
|
+
parent_validations = namespace_stackable[:validations]
|
|
82
|
+
inheritable_setting.route[:saved_validations].concat(parent_validations) if parent_validations.any?
|
|
118
83
|
parent_declared_params = namespace_stackable[:declared_params]
|
|
119
|
-
|
|
120
|
-
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params
|
|
84
|
+
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params.any?
|
|
121
85
|
|
|
122
86
|
endpoints&.each { |e| e.inherit_settings(namespace_stackable) }
|
|
123
87
|
end
|
|
124
88
|
|
|
125
|
-
def require_option(options, key)
|
|
126
|
-
raise Grape::Exceptions::MissingOption.new(key) unless options.key?(key)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def method_name
|
|
130
|
-
[options[:method],
|
|
131
|
-
Namespace.joined_space(namespace_stackable(:namespace)),
|
|
132
|
-
(namespace_stackable(:mount_path) || []).join('/'),
|
|
133
|
-
options[:path].join('/')]
|
|
134
|
-
.join(' ')
|
|
135
|
-
end
|
|
136
|
-
|
|
137
89
|
def routes
|
|
138
|
-
@routes ||= endpoints
|
|
90
|
+
@routes ||= endpoints&.flat_map(&:routes) || to_routes
|
|
139
91
|
end
|
|
140
92
|
|
|
141
93
|
def reset_routes!
|
|
@@ -146,122 +98,79 @@ module Grape
|
|
|
146
98
|
|
|
147
99
|
def mount_in(router)
|
|
148
100
|
if endpoints
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
reset_routes!
|
|
152
|
-
routes.each do |route|
|
|
153
|
-
methods = [route.request_method]
|
|
154
|
-
methods << Grape::Http::Headers::HEAD if !namespace_inheritable(:do_not_route_head) && route.request_method == Grape::Http::Headers::GET
|
|
155
|
-
methods.each do |method|
|
|
156
|
-
route = Grape::Router::Route.new(method, route.origin, **route.attributes.to_h) unless route.request_method == method
|
|
157
|
-
router.append(route.apply(self))
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def to_routes
|
|
164
|
-
route_options = prepare_default_route_attributes
|
|
165
|
-
map_routes do |method, path|
|
|
166
|
-
path = prepare_path(path)
|
|
167
|
-
params = merge_route_options(**route_options.merge(suffix: path.suffix))
|
|
168
|
-
route = Router::Route.new(method, path.path, **params)
|
|
169
|
-
route.apply(self)
|
|
170
|
-
end.flatten
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def prepare_routes_requirements
|
|
174
|
-
{}.merge!(*namespace_stackable(:namespace).map(&:requirements)).tap do |requirements|
|
|
175
|
-
endpoint_requirements = options.dig(:route_options, :requirements)
|
|
176
|
-
requirements.merge!(endpoint_requirements) if endpoint_requirements
|
|
101
|
+
compile!
|
|
102
|
+
return endpoints.each { |e| e.mount_in(router) }
|
|
177
103
|
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def prepare_default_route_attributes
|
|
181
|
-
{
|
|
182
|
-
namespace: namespace,
|
|
183
|
-
version: prepare_version,
|
|
184
|
-
requirements: prepare_routes_requirements,
|
|
185
|
-
prefix: namespace_inheritable(:root_prefix),
|
|
186
|
-
anchor: options[:route_options].fetch(:anchor, true),
|
|
187
|
-
settings: inheritable_setting.route.except(:declared_params, :saved_validations),
|
|
188
|
-
forward_match: options[:forward_match]
|
|
189
|
-
}
|
|
190
|
-
end
|
|
191
104
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def merge_route_options(**default)
|
|
200
|
-
options[:route_options].clone.merge!(**default)
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def map_routes
|
|
204
|
-
options[:method].map { |method| options[:path].map { |path| yield method, path } }
|
|
205
|
-
end
|
|
105
|
+
reset_routes!
|
|
106
|
+
compile!
|
|
107
|
+
routes.each do |route|
|
|
108
|
+
router.append(route.apply(self))
|
|
109
|
+
next if inheritable_setting.namespace_inheritable[:do_not_route_head] || route.request_method != Rack::GET
|
|
206
110
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
111
|
+
route.dup.then do |head_route|
|
|
112
|
+
head_route.convert_to_head_request!
|
|
113
|
+
router.append(head_route.apply(self))
|
|
114
|
+
end
|
|
115
|
+
end
|
|
210
116
|
end
|
|
211
117
|
|
|
212
118
|
def namespace
|
|
213
|
-
@namespace ||= Namespace.joined_space_path(namespace_stackable
|
|
119
|
+
@namespace ||= Namespace.joined_space_path(inheritable_setting.namespace_stackable[:namespace])
|
|
214
120
|
end
|
|
215
121
|
|
|
216
122
|
def call(env)
|
|
217
|
-
lazy_initialize!
|
|
218
123
|
dup.call!(env)
|
|
219
124
|
end
|
|
220
125
|
|
|
221
126
|
def call!(env)
|
|
222
127
|
env[Grape::Env::API_ENDPOINT] = self
|
|
223
128
|
@env = env
|
|
129
|
+
# this adds the helpers only to the instance
|
|
130
|
+
singleton_class.include(@helpers) if @helpers
|
|
224
131
|
@app.call(env)
|
|
225
132
|
end
|
|
226
133
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
134
|
+
def ==(other)
|
|
135
|
+
other.is_a?(self.class) &&
|
|
136
|
+
config == other.config &&
|
|
137
|
+
inheritable_setting == other.inheritable_setting
|
|
231
138
|
end
|
|
139
|
+
alias eql? ==
|
|
232
140
|
|
|
233
|
-
|
|
234
|
-
|
|
141
|
+
# The purpose of this override is solely for stripping internals when an error occurs while calling
|
|
142
|
+
# an endpoint through an api. See https://github.com/ruby-grape/grape/issues/2398
|
|
143
|
+
# Otherwise, it calls super.
|
|
144
|
+
def inspect
|
|
145
|
+
return super unless env
|
|
146
|
+
|
|
147
|
+
"#{self.class} in '#{route.origin}' endpoint"
|
|
235
148
|
end
|
|
236
149
|
|
|
237
150
|
protected
|
|
238
151
|
|
|
239
152
|
def run
|
|
240
|
-
|
|
241
|
-
@
|
|
242
|
-
@request = Grape::Request.new(env, build_params_with: namespace_inheritable(:build_params_with))
|
|
243
|
-
@params = @request.params
|
|
244
|
-
@headers = @request.headers
|
|
153
|
+
instrument_run do
|
|
154
|
+
@request = Grape::Request.new(env, build_params_with: @build_params_with)
|
|
245
155
|
begin
|
|
246
|
-
cookies.read(@request)
|
|
247
|
-
self.class.run_before_each(self)
|
|
248
156
|
run_filters befores, :before
|
|
157
|
+
@before_filter_passed = true
|
|
249
158
|
|
|
250
|
-
if (
|
|
251
|
-
|
|
159
|
+
if env.key?(Grape::Env::GRAPE_ALLOWED_METHODS)
|
|
160
|
+
header['Allow'] = env[Grape::Env::GRAPE_ALLOWED_METHODS].join(', ')
|
|
161
|
+
raise Grape::Exceptions::MethodNotAllowed.new(header) unless options?
|
|
252
162
|
|
|
253
|
-
header 'Allow', allowed_methods
|
|
254
163
|
response_object = ''
|
|
255
164
|
status 204
|
|
256
165
|
else
|
|
257
166
|
run_filters before_validations, :before_validation
|
|
258
|
-
run_validators
|
|
167
|
+
run_validators(request:)
|
|
259
168
|
run_filters after_validations, :after_validation
|
|
260
169
|
response_object = execute
|
|
261
170
|
end
|
|
262
171
|
|
|
263
172
|
run_filters afters, :after
|
|
264
|
-
|
|
173
|
+
build_response_cookies
|
|
265
174
|
|
|
266
175
|
# status verifies body presence when DELETE
|
|
267
176
|
@body ||= response_object
|
|
@@ -276,132 +185,250 @@ module Grape
|
|
|
276
185
|
end
|
|
277
186
|
end
|
|
278
187
|
|
|
279
|
-
def
|
|
280
|
-
|
|
188
|
+
def execute
|
|
189
|
+
return unless source
|
|
281
190
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
helpers: helpers,
|
|
285
|
-
format: namespace_inheritable(:format),
|
|
286
|
-
content_types: namespace_stackable_with_hash(:content_types),
|
|
287
|
-
default_status: namespace_inheritable(:default_error_status),
|
|
288
|
-
rescue_all: namespace_inheritable(:rescue_all),
|
|
289
|
-
rescue_grape_exceptions: namespace_inheritable(:rescue_grape_exceptions),
|
|
290
|
-
default_error_formatter: namespace_inheritable(:default_error_formatter),
|
|
291
|
-
error_formatters: namespace_stackable_with_hash(:error_formatters),
|
|
292
|
-
rescue_options: namespace_stackable_with_hash(:rescue_options) || {},
|
|
293
|
-
rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers) || {},
|
|
294
|
-
base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers) || {},
|
|
295
|
-
all_rescue_handler: namespace_inheritable(:all_rescue_handler),
|
|
296
|
-
grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
|
|
297
|
-
|
|
298
|
-
stack.concat namespace_stackable(:middleware)
|
|
299
|
-
|
|
300
|
-
if namespace_inheritable(:version)
|
|
301
|
-
stack.use Grape::Middleware::Versioner.using(namespace_inheritable(:version_options)[:using]),
|
|
302
|
-
versions: namespace_inheritable(:version)&.flatten,
|
|
303
|
-
version_options: namespace_inheritable(:version_options),
|
|
304
|
-
prefix: namespace_inheritable(:root_prefix),
|
|
305
|
-
mount_path: namespace_stackable(:mount_path).first
|
|
191
|
+
instrument_render do
|
|
192
|
+
source.bind_call(self)
|
|
306
193
|
end
|
|
194
|
+
end
|
|
307
195
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
content_types: namespace_stackable_with_hash(:content_types),
|
|
312
|
-
formatters: namespace_stackable_with_hash(:formatters),
|
|
313
|
-
parsers: namespace_stackable_with_hash(:parsers)
|
|
196
|
+
def run_validators(request:)
|
|
197
|
+
validators = inheritable_setting.route[:saved_validations]
|
|
198
|
+
return if validators.blank?
|
|
314
199
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
200
|
+
validation_exceptions = nil
|
|
201
|
+
|
|
202
|
+
Grape::Validations::ParamScopeTracker.track do
|
|
203
|
+
instrument_run_validators(validators, request) do
|
|
204
|
+
validators.each do |validator|
|
|
205
|
+
validator.validate(request)
|
|
206
|
+
rescue Grape::Exceptions::Validation, Grape::Exceptions::ValidationArrayErrors => e
|
|
207
|
+
(validation_exceptions ||= []) << e
|
|
208
|
+
break if validator.fail_fast?
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
raise Grape::Exceptions::ValidationErrors.new(exceptions: validation_exceptions, headers: header) if validation_exceptions
|
|
318
214
|
end
|
|
319
215
|
|
|
320
|
-
def
|
|
321
|
-
|
|
322
|
-
|
|
216
|
+
def run_filters(filters, type = :other)
|
|
217
|
+
return if filters.blank?
|
|
218
|
+
|
|
219
|
+
instrument_run_filters(filters, type) do
|
|
220
|
+
filters.each { |filter| instance_eval(&filter) }
|
|
221
|
+
end
|
|
323
222
|
end
|
|
324
223
|
|
|
325
|
-
|
|
224
|
+
attr_reader :befores, :before_validations, :after_validations, :afters, :finallies, :config
|
|
326
225
|
|
|
327
|
-
def
|
|
328
|
-
|
|
226
|
+
def options?
|
|
227
|
+
options_route_enabled && env[Rack::REQUEST_METHOD] == Rack::OPTIONS
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
|
|
232
|
+
attr_reader :before_filter_passed
|
|
233
|
+
|
|
234
|
+
# Instrument helpers. Each guards on +listening?+ so that with no subscriber
|
|
235
|
+
# the payload Hash and notification machinery are skipped and the block runs
|
|
236
|
+
# directly (no added allocations); the block is forwarded anonymously so
|
|
237
|
+
# nothing is allocated unless a subscriber is present.
|
|
238
|
+
def instrument_run(&)
|
|
239
|
+
return yield unless ActiveSupport::Notifications.notifier.listening?('endpoint_run.grape')
|
|
240
|
+
|
|
241
|
+
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env:, &)
|
|
329
242
|
end
|
|
330
243
|
|
|
331
|
-
def
|
|
332
|
-
|
|
244
|
+
def instrument_render(&)
|
|
245
|
+
return yield unless ActiveSupport::Notifications.notifier.listening?('endpoint_render.grape')
|
|
246
|
+
|
|
247
|
+
ActiveSupport::Notifications.instrument('endpoint_render.grape', endpoint: self, &)
|
|
333
248
|
end
|
|
334
249
|
|
|
335
|
-
def
|
|
336
|
-
return
|
|
250
|
+
def instrument_run_validators(validators, request, &)
|
|
251
|
+
return yield unless ActiveSupport::Notifications.notifier.listening?('endpoint_run_validators.grape')
|
|
337
252
|
|
|
338
|
-
|
|
339
|
-
|
|
253
|
+
ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators:, request:, &)
|
|
254
|
+
end
|
|
340
255
|
|
|
341
|
-
|
|
342
|
-
|
|
256
|
+
def instrument_run_filters(filters, type, &)
|
|
257
|
+
return yield unless ActiveSupport::Notifications.notifier.listening?('endpoint_run_filters.grape')
|
|
343
258
|
|
|
344
|
-
|
|
345
|
-
end
|
|
259
|
+
ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters:, type:, &)
|
|
346
260
|
end
|
|
347
261
|
|
|
348
|
-
def
|
|
349
|
-
|
|
262
|
+
def compile!
|
|
263
|
+
@app = config.app || build_stack
|
|
264
|
+
warn_unauthenticated_mounted_app
|
|
265
|
+
@helpers = build_helpers
|
|
266
|
+
stackable = inheritable_setting.namespace_stackable
|
|
267
|
+
@befores = stackable[:befores]
|
|
268
|
+
@before_validations = stackable[:before_validations]
|
|
269
|
+
@after_validations = stackable[:after_validations]
|
|
270
|
+
@afters = stackable[:afters]
|
|
271
|
+
@finallies = stackable[:finallies]
|
|
272
|
+
@build_params_with = inheritable_setting.namespace_inheritable[:build_params_with]
|
|
273
|
+
end
|
|
350
274
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
275
|
+
def to_routes
|
|
276
|
+
route_options = config.route_options
|
|
277
|
+
default_route_options = prepare_default_route_attributes(route_options)
|
|
278
|
+
complete_route_options = route_options.merge(default_route_options)
|
|
279
|
+
path_settings = prepare_default_path_settings
|
|
280
|
+
|
|
281
|
+
config.http_methods.flat_map do |method|
|
|
282
|
+
config.path.map do |path|
|
|
283
|
+
prepared_path = Path.new(path, default_route_options[:namespace], path_settings)
|
|
284
|
+
pattern = Grape::Router::Pattern.new(
|
|
285
|
+
origin: prepared_path.origin,
|
|
286
|
+
suffix: prepared_path.suffix,
|
|
287
|
+
anchor: default_route_options[:anchor],
|
|
288
|
+
params: route_options[:params],
|
|
289
|
+
format: config.format,
|
|
290
|
+
version: default_route_options[:version],
|
|
291
|
+
requirements: default_route_options[:requirements]
|
|
292
|
+
)
|
|
293
|
+
Grape::Router::Route.new(self, method, pattern, complete_route_options)
|
|
360
294
|
end
|
|
361
295
|
end
|
|
296
|
+
end
|
|
362
297
|
|
|
363
|
-
|
|
298
|
+
# True when a bare Rack app (anything that isn't a Grape app) is mounted at
|
|
299
|
+
# this endpoint. Such an app is called directly and matched by path prefix
|
|
300
|
+
# rather than an anchored route.
|
|
301
|
+
def bare_rack_app?
|
|
302
|
+
config.app && !config.app.is_a?(Grape::Mountable)
|
|
364
303
|
end
|
|
365
304
|
|
|
366
|
-
def
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
305
|
+
def prepare_default_route_attributes(route_options)
|
|
306
|
+
{
|
|
307
|
+
namespace:,
|
|
308
|
+
version: prepare_version(inheritable_setting.namespace_inheritable[:version]),
|
|
309
|
+
requirements: prepare_routes_requirements(route_options[:requirements]),
|
|
310
|
+
prefix: inheritable_setting.namespace_inheritable[:root_prefix],
|
|
311
|
+
anchor: route_options.fetch(:anchor, true),
|
|
312
|
+
settings: inheritable_setting.route.except(:declared_params, :saved_validations),
|
|
313
|
+
forward_match: config.forward_match
|
|
314
|
+
}
|
|
372
315
|
end
|
|
373
316
|
|
|
374
|
-
def
|
|
375
|
-
namespace_stackable
|
|
317
|
+
def prepare_default_path_settings
|
|
318
|
+
namespace_stackable_hash = inheritable_setting.namespace_stackable.to_hash
|
|
319
|
+
namespace_inheritable_hash = inheritable_setting.namespace_inheritable.to_hash
|
|
320
|
+
namespace_stackable_hash.merge!(namespace_inheritable_hash)
|
|
376
321
|
end
|
|
377
322
|
|
|
378
|
-
def
|
|
379
|
-
namespace_stackable(
|
|
323
|
+
def prepare_routes_requirements(route_options_requirements)
|
|
324
|
+
namespace_requirements = inheritable_setting.namespace_stackable[:namespace].filter_map(&:requirements)
|
|
325
|
+
namespace_requirements << route_options_requirements if route_options_requirements.present?
|
|
326
|
+
namespace_requirements.reduce({}, :merge)
|
|
380
327
|
end
|
|
381
328
|
|
|
382
|
-
def
|
|
383
|
-
|
|
329
|
+
def prepare_version(namespace_inheritable_version)
|
|
330
|
+
return if namespace_inheritable_version.blank?
|
|
331
|
+
|
|
332
|
+
namespace_inheritable_version.length == 1 ? namespace_inheritable_version.first : namespace_inheritable_version
|
|
384
333
|
end
|
|
385
334
|
|
|
386
|
-
def
|
|
387
|
-
|
|
335
|
+
def build_stack
|
|
336
|
+
stack = Grape::Middleware::Stack.new
|
|
337
|
+
|
|
338
|
+
content_types = inheritable_setting.namespace_stackable_with_hash(:content_types)
|
|
339
|
+
format = inheritable_setting.namespace_inheritable[:format]
|
|
340
|
+
|
|
341
|
+
stack.use Rack::Head
|
|
342
|
+
stack.use Rack::Lint if lint?
|
|
343
|
+
stack.use Grape::Middleware::Error, **error_middleware_options(format, content_types)
|
|
344
|
+
|
|
345
|
+
stack.concat inheritable_setting.namespace_stackable[:middleware]
|
|
346
|
+
|
|
347
|
+
if inheritable_setting.namespace_inheritable[:version].present?
|
|
348
|
+
version_options = inheritable_setting.namespace_inheritable[:version_options]
|
|
349
|
+
stack.use Grape::Middleware::Versioner.using(version_options.using),
|
|
350
|
+
versions: inheritable_setting.namespace_inheritable[:version].flatten,
|
|
351
|
+
version_options:,
|
|
352
|
+
prefix: inheritable_setting.namespace_inheritable[:root_prefix],
|
|
353
|
+
mount_path: inheritable_setting.namespace_stackable[:mount_path].first
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
stack.use Grape::Middleware::Formatter,
|
|
357
|
+
format:,
|
|
358
|
+
default_format: inheritable_setting.namespace_inheritable[:default_format] || :txt,
|
|
359
|
+
content_types:,
|
|
360
|
+
formatters: inheritable_setting.namespace_stackable_with_hash(:formatters),
|
|
361
|
+
parsers: inheritable_setting.namespace_stackable_with_hash(:parsers)
|
|
362
|
+
|
|
363
|
+
builder = stack.build
|
|
364
|
+
builder.run ->(env) { env[Grape::Env::API_ENDPOINT].run }
|
|
365
|
+
builder.to_app
|
|
388
366
|
end
|
|
389
367
|
|
|
390
|
-
def
|
|
391
|
-
|
|
368
|
+
def error_middleware_options(format, content_types)
|
|
369
|
+
ns_inh = inheritable_setting.namespace_inheritable
|
|
370
|
+
ns_stack = inheritable_setting
|
|
371
|
+
{
|
|
372
|
+
format:,
|
|
373
|
+
content_types:,
|
|
374
|
+
default_status: ns_inh[:default_error_status],
|
|
375
|
+
rescue_all: ns_inh[:rescue_all],
|
|
376
|
+
rescue_grape_exceptions: ns_inh[:rescue_grape_exceptions],
|
|
377
|
+
default_error_formatter: ns_inh[:default_error_formatter],
|
|
378
|
+
error_formatters: ns_stack.namespace_stackable_with_hash(:error_formatters),
|
|
379
|
+
rescue_options: ns_stack.namespace_stackable[:rescue_options]&.last,
|
|
380
|
+
rescue_handlers: merged_reverse_stackable(:rescue_handlers),
|
|
381
|
+
base_only_rescue_handlers: merged_reverse_stackable(:base_only_rescue_handlers),
|
|
382
|
+
all_rescue_handler: ns_inh[:all_rescue_handler],
|
|
383
|
+
grape_exceptions_rescue_handler: ns_inh[:grape_exceptions_rescue_handler],
|
|
384
|
+
internal_grape_exceptions_rescue_handler: ns_inh[:internal_grape_exceptions_rescue_handler]
|
|
385
|
+
}
|
|
392
386
|
end
|
|
393
387
|
|
|
394
|
-
def
|
|
395
|
-
|
|
388
|
+
def build_helpers
|
|
389
|
+
helpers = inheritable_setting.namespace_stackable[:helpers]
|
|
390
|
+
return if helpers.empty?
|
|
391
|
+
|
|
392
|
+
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# A bare Rack app mounted with +mount+ is called directly (see +compile!+):
|
|
396
|
+
# it does not go through +build_stack+, so the API's authentication
|
|
397
|
+
# middleware never runs and the mount is reachable unauthenticated. Mounted
|
|
398
|
+
# Grape APIs are unaffected because they rebuild their own stack from the
|
|
399
|
+
# inherited settings. Warn so this bypass isn't silent.
|
|
400
|
+
def warn_unauthenticated_mounted_app
|
|
401
|
+
return unless bare_rack_app?
|
|
402
|
+
return unless inheritable_setting.namespace_inheritable[:auth]
|
|
403
|
+
|
|
404
|
+
warn "Grape: #{config.app} is mounted under an API that declares authentication, but authentication " \
|
|
405
|
+
'middleware does not wrap mounted Rack applications. Requests to this mount are not authenticated by Grape.'
|
|
406
|
+
end
|
|
396
407
|
|
|
397
|
-
|
|
398
|
-
|
|
408
|
+
def build_response_cookies
|
|
409
|
+
return unless request.cookies?
|
|
410
|
+
|
|
411
|
+
response_cookies do |name, value|
|
|
412
|
+
cookie_value = value.is_a?(Hash) ? value : { value: }
|
|
413
|
+
Rack::Utils.set_cookie_header! header, name, cookie_value
|
|
399
414
|
end
|
|
400
415
|
end
|
|
401
416
|
|
|
402
|
-
def
|
|
403
|
-
|
|
404
|
-
|
|
417
|
+
def lint?
|
|
418
|
+
inheritable_setting.namespace_inheritable[:lint] || Grape.config.lint
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Merge a reverse-stackable handler map (as written by +rescue_from+) into a
|
|
422
|
+
# single Hash. The reverse store lists child-scope handlers before inherited
|
|
423
|
+
# ones, and the first-wins merge keeps the child's handler for a given
|
|
424
|
+
# class, so a nested +rescue_from+ overrides an outer one.
|
|
425
|
+
def merged_reverse_stackable(key)
|
|
426
|
+
handlers = inheritable_setting.namespace_reverse_stackable[key]
|
|
427
|
+
return if handlers.blank?
|
|
428
|
+
|
|
429
|
+
handlers.each_with_object({}) do |handler, result|
|
|
430
|
+
result.merge!(handler) { |_k, s1, _s2| s1 }
|
|
431
|
+
end
|
|
405
432
|
end
|
|
406
433
|
end
|
|
407
434
|
end
|