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,19 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/exceptions/base'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module Exceptions
|
|
7
|
-
class Validation <
|
|
8
|
-
|
|
5
|
+
class Validation < Base
|
|
6
|
+
EMPTY_BACKTRACE = [].freeze
|
|
7
|
+
|
|
8
|
+
attr_reader :params, :message_key
|
|
9
|
+
|
|
10
|
+
def initialize(params:, message: nil, status: nil, headers: nil)
|
|
11
|
+
@params = Array(params)
|
|
12
|
+
translated =
|
|
13
|
+
if message
|
|
14
|
+
@message_key = case message
|
|
15
|
+
when Symbol then message
|
|
16
|
+
when Hash then message[:key]
|
|
17
|
+
end
|
|
18
|
+
translate_message(message)
|
|
19
|
+
end
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
super(**args)
|
|
21
|
+
super(status:, message: translated, headers:)
|
|
22
|
+
# Pre-seed the backtrace so Ruby's raise skips capture. Validation errors are
|
|
23
|
+
# a hot path (raised per bad attribute) and end up as 400 Bad Request responses;
|
|
24
|
+
# backtraces here point into Grape internals and have no diagnostic value.
|
|
25
|
+
set_backtrace(EMPTY_BACKTRACE)
|
|
17
26
|
end
|
|
18
27
|
|
|
19
28
|
# Remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
|
@@ -21,6 +30,14 @@ module Grape
|
|
|
21
30
|
def as_json(*_args)
|
|
22
31
|
to_s
|
|
23
32
|
end
|
|
33
|
+
|
|
34
|
+
# Returns +self+ so callers (e.g. +ValidationErrors#initialize+) can treat
|
|
35
|
+
# a single +Validation+ and a +ValidationArrayErrors+ wrapper uniformly via
|
|
36
|
+
# +flat_map(&:errors)+ — Array returns flatten in, non-Array returns
|
|
37
|
+
# (i.e. this +self+) append as one element.
|
|
38
|
+
def errors
|
|
39
|
+
self
|
|
40
|
+
end
|
|
24
41
|
end
|
|
25
42
|
end
|
|
26
43
|
end
|
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class ValidationArrayErrors < Base
|
|
6
|
+
EMPTY_BACKTRACE = [].freeze
|
|
7
|
+
|
|
6
8
|
attr_reader :errors
|
|
7
9
|
|
|
8
10
|
def initialize(errors)
|
|
11
|
+
super()
|
|
9
12
|
@errors = errors
|
|
13
|
+
# Skip backtrace capture — see Grape::Exceptions::Validation for rationale.
|
|
14
|
+
set_backtrace(EMPTY_BACKTRACE)
|
|
10
15
|
end
|
|
11
16
|
end
|
|
12
17
|
end
|
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/exceptions/base'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module Exceptions
|
|
7
|
-
class ValidationErrors <
|
|
8
|
-
ERRORS_FORMAT_KEY = 'grape.errors.format'
|
|
9
|
-
DEFAULT_ERRORS_FORMAT = '%{attributes} %{message}'
|
|
10
|
-
|
|
11
|
-
include Enumerable
|
|
12
|
-
|
|
5
|
+
class ValidationErrors < Base
|
|
13
6
|
attr_reader :errors
|
|
14
7
|
|
|
15
|
-
def initialize(
|
|
16
|
-
@errors = errors.group_by(&:params)
|
|
17
|
-
super
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def each
|
|
21
|
-
errors.each_pair do |attribute, errors|
|
|
22
|
-
errors.each do |error|
|
|
23
|
-
yield attribute, error
|
|
24
|
-
end
|
|
25
|
-
end
|
|
8
|
+
def initialize(exceptions: [], headers: {})
|
|
9
|
+
@errors = exceptions.flat_map(&:errors).group_by(&:params)
|
|
10
|
+
super(message: full_messages.join(', '), status: 400, headers:)
|
|
26
11
|
end
|
|
27
12
|
|
|
28
13
|
def as_json(**_opts)
|
|
@@ -39,17 +24,28 @@ module Grape
|
|
|
39
24
|
end
|
|
40
25
|
|
|
41
26
|
def full_messages
|
|
42
|
-
messages =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
27
|
+
messages = errors.flat_map do |attributes, errs|
|
|
28
|
+
errs.map do |error|
|
|
29
|
+
translate(
|
|
30
|
+
:format,
|
|
31
|
+
scope: 'grape.errors',
|
|
32
|
+
default: '%<attributes>s %<message>s',
|
|
33
|
+
attributes: translate_attributes(attributes),
|
|
34
|
+
message: error.message
|
|
35
|
+
)
|
|
36
|
+
end
|
|
49
37
|
end
|
|
50
38
|
messages.uniq!
|
|
51
39
|
messages
|
|
52
40
|
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def translate_attributes(keys)
|
|
45
|
+
keys.map do |key|
|
|
46
|
+
translate(key, scope: 'grape.errors.attributes', default: key.to_s)
|
|
47
|
+
end.join(', ')
|
|
48
|
+
end
|
|
53
49
|
end
|
|
54
50
|
end
|
|
55
51
|
end
|
data/lib/grape/formatter/json.rb
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Formatter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
class Json < Base
|
|
6
|
+
def self.call(object, _env)
|
|
7
|
+
return object.to_s if object.is_a?(Grape::PrecompiledJson)
|
|
8
|
+
return object.to_json if object.respond_to?(:to_json)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
end
|
|
10
|
+
::Grape::Json.dump(object)
|
|
12
11
|
end
|
|
13
12
|
end
|
|
14
13
|
end
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Formatter
|
|
5
|
-
|
|
5
|
+
class SerializableHash < Base
|
|
6
6
|
class << self
|
|
7
7
|
def call(object, _env)
|
|
8
|
+
return object.to_s if object.is_a?(Grape::PrecompiledJson)
|
|
8
9
|
return object if object.is_a?(String)
|
|
9
10
|
return ::Grape::Json.dump(serialize(object)) if serializable?(object)
|
|
10
11
|
return object.to_json if object.respond_to?(:to_json)
|
|
@@ -19,15 +20,11 @@ module Grape
|
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def serialize(object)
|
|
22
|
-
if object.respond_to?
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
object.transform_values { |v| serialize(v) }
|
|
28
|
-
else
|
|
29
|
-
object
|
|
30
|
-
end
|
|
23
|
+
return object.serializable_hash if object.respond_to?(:serializable_hash)
|
|
24
|
+
return object.map(&:serializable_hash) if array_serializable?(object)
|
|
25
|
+
return object.transform_values { |v| serialize(v) } if object.is_a?(Hash)
|
|
26
|
+
|
|
27
|
+
object
|
|
31
28
|
end
|
|
32
29
|
|
|
33
30
|
def array_serializable?(object)
|
data/lib/grape/formatter/txt.rb
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Formatter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
|
|
9
|
-
end
|
|
5
|
+
class Txt < Base
|
|
6
|
+
def self.call(object, _env)
|
|
7
|
+
object.respond_to?(:to_txt) ? object.to_txt : object.to_s
|
|
10
8
|
end
|
|
11
9
|
end
|
|
12
10
|
end
|
data/lib/grape/formatter/xml.rb
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Formatter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return object.to_xml if object.respond_to?(:to_xml)
|
|
5
|
+
class Xml < Base
|
|
6
|
+
def self.call(object, _env)
|
|
7
|
+
return object.to_xml if object.respond_to?(:to_xml)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
end
|
|
9
|
+
raise Grape::Exceptions::InvalidFormatter.new(object.class, 'xml')
|
|
12
10
|
end
|
|
13
11
|
end
|
|
14
12
|
end
|
data/lib/grape/formatter.rb
CHANGED
|
@@ -2,34 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Formatter
|
|
5
|
-
extend Util::
|
|
5
|
+
extend Grape::Util::Registry
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
def builtin_formatters
|
|
9
|
-
@builtin_formatters ||= {
|
|
10
|
-
json: Grape::Formatter::Json,
|
|
11
|
-
jsonapi: Grape::Formatter::Json,
|
|
12
|
-
serializable_hash: Grape::Formatter::SerializableHash,
|
|
13
|
-
txt: Grape::Formatter::Txt,
|
|
14
|
-
xml: Grape::Formatter::Xml
|
|
15
|
-
}
|
|
16
|
-
end
|
|
7
|
+
module_function
|
|
17
8
|
|
|
18
|
-
|
|
19
|
-
builtin_formatters.merge(default_elements).merge!(options[:formatters] || {})
|
|
20
|
-
end
|
|
9
|
+
DEFAULT_LAMBDA_FORMATTER = ->(obj, _env) { obj }
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
->(obj, _env) { obj }
|
|
27
|
-
when Symbol
|
|
28
|
-
method(spec)
|
|
29
|
-
else
|
|
30
|
-
spec
|
|
31
|
-
end
|
|
32
|
-
end
|
|
11
|
+
def formatter_for(api_format, formatters)
|
|
12
|
+
return formatters[api_format] if formatters&.key?(api_format)
|
|
13
|
+
|
|
14
|
+
registry[api_format] || DEFAULT_LAMBDA_FORMATTER
|
|
33
15
|
end
|
|
34
16
|
end
|
|
35
17
|
end
|
data/lib/grape/json.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
if defined?(::MultiJSON)
|
|
5
|
+
# Since multi_json 1.21.0, MultiJSON.dump is deprecated in favor of
|
|
6
|
+
# MultiJSON.generate (removed in 2.0). Keep Grape's dump surface but route
|
|
7
|
+
# it to the non-deprecated name — identical output, no deprecation warning.
|
|
8
|
+
# https://github.com/sferik/multi_json/blob/v1.21.1/CHANGELOG.md#deprecated
|
|
9
|
+
module Json
|
|
10
|
+
ParseError = ::MultiJSON::ParseError
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def dump(object)
|
|
14
|
+
::MultiJSON.generate(object)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# parse is not deprecated; it's re-exposed (not renamed) because this
|
|
18
|
+
# facade is its own module and no longer inherits MultiJSON's methods.
|
|
19
|
+
def parse(source)
|
|
20
|
+
::MultiJSON.parse(source)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
elsif defined?(::MultiJson)
|
|
25
|
+
# Legacy multi_json (< 1.21) predates generate/parse and only exposes
|
|
26
|
+
# dump/load. Map Grape's surface onto them so the call sites stay
|
|
27
|
+
# engine-agnostic (these names are not deprecated on < 1.21).
|
|
28
|
+
module Json
|
|
29
|
+
# Mutually exclusive with the MultiJSON branch above; only one runs.
|
|
30
|
+
ParseError = ::MultiJson::ParseError # rubocop:disable Lint/ConstantReassignment
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
def dump(object)
|
|
34
|
+
::MultiJson.dump(object)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def parse(source)
|
|
38
|
+
::MultiJson.load(source)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
Json = ::JSON
|
|
44
|
+
Json::ParseError = Json::ParserError
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/grape/locale/en.yml
CHANGED
|
@@ -1,55 +1,57 @@
|
|
|
1
|
+
---
|
|
1
2
|
en:
|
|
2
3
|
grape:
|
|
3
4
|
errors:
|
|
4
|
-
format:
|
|
5
|
+
format: '%{attributes} %{message}'
|
|
5
6
|
messages:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
regexp: 'is invalid'
|
|
7
|
+
all_or_none: 'provide all or none of parameters'
|
|
8
|
+
at_least_one: 'are missing, at least one parameter must be provided'
|
|
9
9
|
blank: 'is empty'
|
|
10
|
-
|
|
10
|
+
coerce: 'is invalid'
|
|
11
|
+
exactly_one: 'are missing, exactly one parameter must be provided'
|
|
11
12
|
except_values: 'has a value not allowed'
|
|
12
|
-
same_as: 'is not the same as %{parameter}'
|
|
13
|
-
missing_vendor_option:
|
|
14
|
-
problem: 'missing :vendor option'
|
|
15
|
-
summary: 'when version using header, you must specify :vendor option'
|
|
16
|
-
resolution: "eg: version 'v1', using: :header, vendor: 'twitter'"
|
|
17
|
-
missing_mime_type:
|
|
18
|
-
problem: 'missing mime type for %{new_format}'
|
|
19
|
-
resolution:
|
|
20
|
-
"you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES
|
|
21
|
-
or add your own with content_type :%{new_format}, 'application/%{new_format}'
|
|
22
|
-
"
|
|
23
|
-
invalid_with_option_for_represent:
|
|
24
|
-
problem: 'you must specify an entity class in the :with option'
|
|
25
|
-
resolution: 'eg: represent User, :with => Entity::User'
|
|
26
|
-
missing_option: 'you must specify :%{option} options'
|
|
27
|
-
invalid_formatter: 'cannot convert %{klass} to %{to_format}'
|
|
28
|
-
invalid_versioner_option:
|
|
29
|
-
problem: 'unknown :using for versioner: %{strategy}'
|
|
30
|
-
resolution: 'available strategy for :using is :path, :header, :accept_version_header, :param'
|
|
31
|
-
unknown_validator: 'unknown validator: %{validator_type}'
|
|
32
|
-
unknown_options: 'unknown options: %{options}'
|
|
33
|
-
unknown_parameter: 'unknown parameter: %{param}'
|
|
34
13
|
incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
|
|
35
|
-
|
|
36
|
-
at_least_one: 'are missing, at least one parameter must be provided'
|
|
37
|
-
exactly_one: 'are missing, exactly one parameter must be provided'
|
|
38
|
-
all_or_none: 'provide all or none of parameters'
|
|
39
|
-
missing_group_type: 'group type is required'
|
|
40
|
-
unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
|
|
41
|
-
invalid_message_body:
|
|
42
|
-
problem: "message body does not match declared format"
|
|
43
|
-
resolution:
|
|
44
|
-
"when specifying %{body_format} as content-type, you must pass valid
|
|
45
|
-
%{body_format} in the request's 'body'
|
|
46
|
-
"
|
|
47
|
-
empty_message_body: 'empty message body supplied with %{body_format} content-type'
|
|
48
|
-
too_many_multipart_files: "the number of uploaded files exceeded the system's configured limit (%{limit})"
|
|
14
|
+
internal_server_error: 'Internal Server Error'
|
|
49
15
|
invalid_accept_header:
|
|
50
16
|
problem: 'invalid accept header'
|
|
51
17
|
resolution: '%{message}'
|
|
18
|
+
invalid_formatter: 'cannot convert %{klass} to %{to_format}'
|
|
19
|
+
invalid_message_body:
|
|
20
|
+
problem: 'message body does not match declared format'
|
|
21
|
+
resolution: 'when specifying %{body_format} as content-type, you must pass valid %{body_format} in the request''s ''body'' '
|
|
22
|
+
invalid_response: 'Invalid response'
|
|
52
23
|
invalid_version_header:
|
|
53
24
|
problem: 'invalid version header'
|
|
54
25
|
resolution: '%{message}'
|
|
55
|
-
|
|
26
|
+
invalid_versioner_option:
|
|
27
|
+
problem: 'unknown :using for versioner: %{strategy}'
|
|
28
|
+
resolution: 'available strategy for :using is :path, :header, :accept_version_header, :param'
|
|
29
|
+
invalid_with_option_for_represent:
|
|
30
|
+
problem: 'you must specify an entity class in the :with option'
|
|
31
|
+
resolution: 'eg: represent User, :with => Entity::User'
|
|
32
|
+
length: 'is expected to have length within %{min} and %{max}'
|
|
33
|
+
length_is: 'is expected to have length exactly equal to %{is}'
|
|
34
|
+
length_max: 'is expected to have length less than or equal to %{max}'
|
|
35
|
+
length_min: 'is expected to have length greater than or equal to %{min}'
|
|
36
|
+
missing_group_type: 'group type is required'
|
|
37
|
+
missing_mime_type:
|
|
38
|
+
problem: 'missing mime type for %{new_format}'
|
|
39
|
+
resolution: 'you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES or add your own with content_type :%{new_format}, ''application/%{new_format}'' '
|
|
40
|
+
missing_option: 'you must specify :%{option} options'
|
|
41
|
+
missing_vendor_option:
|
|
42
|
+
problem: 'missing :vendor option'
|
|
43
|
+
resolution: 'eg: version ''v1'', using: :header, vendor: ''twitter'''
|
|
44
|
+
summary: 'when version using header, you must specify :vendor option'
|
|
45
|
+
mutual_exclusion: 'are mutually exclusive'
|
|
46
|
+
oneof: 'does not match any of the allowed schemas'
|
|
47
|
+
presence: 'is missing'
|
|
48
|
+
regexp: 'is invalid'
|
|
49
|
+
same_as: 'is not the same as %{parameter}'
|
|
50
|
+
unknown_auth_strategy: 'unknown auth strategy: %{strategy}'
|
|
51
|
+
unknown_error_formatter: 'unknown error formatter: %{error_formatter_type}'
|
|
52
|
+
unknown_options: 'unknown options: %{options}'
|
|
53
|
+
unknown_parameter: 'unknown parameter: %{param}'
|
|
54
|
+
unknown_params_builder: 'unknown params_builder: %{params_builder_type}'
|
|
55
|
+
unknown_validator: 'unknown validator: %{validator_type}'
|
|
56
|
+
unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
|
|
57
|
+
values: 'does not have a valid value'
|
|
@@ -1,44 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'rack/auth/basic'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module Middleware
|
|
7
5
|
module Auth
|
|
8
|
-
class Base
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
class Base < Grape::Middleware::Base
|
|
7
|
+
def initialize(app, **options)
|
|
8
|
+
super
|
|
9
|
+
return unless options.key?(:type)
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@options = options.shift
|
|
11
|
+
@auth_strategy = Grape::Middleware::Auth::Strategies[options[:type]]
|
|
12
|
+
raise Grape::Exceptions::UnknownAuthStrategy.new(strategy: options[:type]) unless @auth_strategy
|
|
16
13
|
end
|
|
17
14
|
|
|
18
|
-
def call(env)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
self.env = env
|
|
24
|
-
|
|
25
|
-
if options.key?(:type)
|
|
26
|
-
auth_proc = options[:proc]
|
|
27
|
-
auth_proc_context = context
|
|
28
|
-
|
|
29
|
-
strategy_info = Grape::Middleware::Auth::Strategies[options[:type]]
|
|
30
|
-
|
|
31
|
-
throw(:error, status: 401, message: 'API Authorization Failed.') if strategy_info.blank?
|
|
32
|
-
|
|
33
|
-
strategy = strategy_info.create(@app, options) do |*args|
|
|
34
|
-
auth_proc_context.instance_exec(*args, &auth_proc)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
strategy.call(env)
|
|
38
|
-
|
|
39
|
-
else
|
|
40
|
-
app.call(env)
|
|
41
|
-
end
|
|
15
|
+
def call!(env)
|
|
16
|
+
@env = env
|
|
17
|
+
@auth_strategy.create(app, options) do |*args|
|
|
18
|
+
context.instance_exec(*args, &options[:proc])
|
|
19
|
+
end.call(env)
|
|
42
20
|
end
|
|
43
21
|
end
|
|
44
22
|
end
|
|
@@ -1,45 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'rack/auth/basic'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module Middleware
|
|
7
5
|
module Auth
|
|
8
6
|
module DSL
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
module ClassMethods
|
|
12
|
-
# Add an authentication type to the API. Currently
|
|
13
|
-
# only `:http_basic`, `:http_digest` are supported.
|
|
14
|
-
def auth(type = nil, options = {}, &block)
|
|
15
|
-
if type
|
|
16
|
-
namespace_inheritable(:auth, options.reverse_merge(type: type.to_sym, proc: block))
|
|
17
|
-
use Grape::Middleware::Auth::Base, namespace_inheritable(:auth)
|
|
18
|
-
else
|
|
19
|
-
namespace_inheritable(:auth)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Add HTTP Basic authorization to the API.
|
|
24
|
-
#
|
|
25
|
-
# @param [Hash] options A hash of options.
|
|
26
|
-
# @option options [String] :realm "API Authorization" The HTTP Basic realm.
|
|
27
|
-
def http_basic(options = {}, &block)
|
|
28
|
-
options[:realm] ||= 'API Authorization'
|
|
29
|
-
auth :http_basic, options, &block
|
|
30
|
-
end
|
|
7
|
+
def auth(type = nil, **options, &block)
|
|
8
|
+
return inheritable_setting.auth unless type
|
|
31
9
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if options[:realm].respond_to?(:values_at)
|
|
36
|
-
options[:realm][:opaque] ||= 'secret'
|
|
37
|
-
else
|
|
38
|
-
options[:opaque] ||= 'secret'
|
|
39
|
-
end
|
|
10
|
+
inheritable_setting.auth = { type: type.to_sym, proc: block }.merge!(options)
|
|
11
|
+
use Grape::Middleware::Auth::Base, inheritable_setting.auth
|
|
12
|
+
end
|
|
40
13
|
|
|
41
|
-
|
|
42
|
-
|
|
14
|
+
# Add HTTP Basic authorization to the API.
|
|
15
|
+
#
|
|
16
|
+
# @param options [Hash] a hash of options
|
|
17
|
+
# @option options [String] :realm "API Authorization" the HTTP Basic realm
|
|
18
|
+
def http_basic(**options, &)
|
|
19
|
+
options[:realm] ||= 'API Authorization'
|
|
20
|
+
auth(:http_basic, **options, &)
|
|
43
21
|
end
|
|
44
22
|
end
|
|
45
23
|
end
|
|
@@ -12,8 +12,7 @@ module Grape
|
|
|
12
12
|
|
|
13
13
|
def auth_strategies
|
|
14
14
|
@auth_strategies ||= {
|
|
15
|
-
http_basic: StrategyInfo.new(Rack::Auth::Basic, ->(settings) { [settings[:realm]] })
|
|
16
|
-
http_digest: StrategyInfo.new(Rack::Auth::Digest::MD5, ->(settings) { [settings[:realm], settings[:opaque]] })
|
|
15
|
+
http_basic: StrategyInfo.new(Rack::Auth::Basic, ->(settings) { [settings[:realm]] })
|
|
17
16
|
}
|
|
18
17
|
end
|
|
19
18
|
|