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
|
@@ -3,55 +3,71 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Validations
|
|
5
5
|
class AttributesIterator
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def initialize(
|
|
6
|
+
# +attrs+ and +scope+ are static per validator; only +params+ varies
|
|
7
|
+
# per request, so an instance can be built once and reused (it keeps
|
|
8
|
+
# no request-derived state). Reused instances are shared across
|
|
9
|
+
# threads, so +each+ must stay free of mutable instance state.
|
|
10
|
+
def initialize(attrs, scope)
|
|
11
|
+
@attrs = attrs
|
|
11
12
|
@scope = scope
|
|
12
|
-
@attrs = validator.attrs
|
|
13
|
-
@original_params = scope.params(params)
|
|
14
|
-
@params = Array.wrap(@original_params)
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
def each(&
|
|
18
|
-
|
|
15
|
+
def each(params, &)
|
|
16
|
+
original_params = @scope.params(params)
|
|
17
|
+
# because we need recursion for nested arrays
|
|
18
|
+
do_each(Array.wrap(original_params), original_params, &)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
|
|
23
|
-
def do_each(params_to_process,
|
|
23
|
+
def do_each(params_to_process, original_params, parent_indices = [], &block)
|
|
24
24
|
params_to_process.each_with_index do |resource_params, index|
|
|
25
25
|
# when we get arrays of arrays it means that target element located inside array
|
|
26
|
-
# we need this because we want to know parent arrays
|
|
26
|
+
# we need this because we want to know parent arrays indices
|
|
27
27
|
if resource_params.is_a?(Array)
|
|
28
|
-
do_each(resource_params, [index] +
|
|
28
|
+
do_each(resource_params, original_params, [index] + parent_indices, &block)
|
|
29
29
|
next
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
if @scope.type == Array
|
|
33
|
-
next unless
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
next unless original_params.is_a?(Array) # do not validate content of array if it isn't array
|
|
34
|
+
|
|
35
|
+
store_indices(@scope, index, parent_indices)
|
|
36
|
+
elsif original_params.is_a?(Array)
|
|
37
|
+
# Lateral scope (no @element) whose params resolved to an array —
|
|
38
|
+
# delegate index tracking to the nearest array-typed ancestor so
|
|
39
|
+
# that full_name produces the correct bracketed index.
|
|
40
|
+
target = @scope.nearest_array_ancestor
|
|
41
|
+
store_indices(target, index, parent_indices) if target
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
yield_attributes(resource_params,
|
|
44
|
+
yield_attributes(resource_params, &block)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def store_indices(target_scope, index, parent_indices)
|
|
49
|
+
# No tracker means we're outside a ParamScopeTracker.track block (e.g.
|
|
50
|
+
# a unit test that invokes a validator directly). Index tracking is
|
|
51
|
+
# skipped — full_name will produce bracket-less names — but validation
|
|
52
|
+
# continues rather than crashing.
|
|
53
|
+
tracker = ParamScopeTracker.current or return
|
|
54
|
+
parent_scope = target_scope.parent
|
|
55
|
+
parent_indices.each do |parent_index|
|
|
56
|
+
break unless parent_scope
|
|
57
|
+
|
|
58
|
+
tracker.store_index(parent_scope, parent_index)
|
|
59
|
+
parent_scope = parent_scope.parent
|
|
45
60
|
end
|
|
61
|
+
tracker.store_index(target_scope, index)
|
|
46
62
|
end
|
|
47
63
|
|
|
48
|
-
def yield_attributes(_resource_params
|
|
64
|
+
def yield_attributes(_resource_params)
|
|
49
65
|
raise NotImplementedError
|
|
50
66
|
end
|
|
51
67
|
|
|
52
|
-
# This is a special case so that we can ignore
|
|
53
|
-
# values are missing lower down. Unfortunately we can remove this
|
|
54
|
-
#
|
|
68
|
+
# This is a special case so that we can ignore trees where option
|
|
69
|
+
# values are missing lower down. Unfortunately we can't remove this
|
|
70
|
+
# at the parameter parsing stage as they are required to ensure
|
|
55
71
|
# the correct indexing is maintained
|
|
56
72
|
def skip?(val)
|
|
57
73
|
val == Grape::DSL::Parameters::EmptyOptionalValue
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Validations
|
|
5
|
+
# Immutable value object describing how a parameter is coerced. Assembled
|
|
6
|
+
# by {ValidationsSpec#coerce_options} from the parsed +type+/+coerce_with+/
|
|
7
|
+
# +coerce_message+ declaration — never written by the user — and consumed
|
|
8
|
+
# by {ParamsScope#check_coerce_with} / {ParamsScope#validate_coerce} and by
|
|
9
|
+
# {Validators::Validators::CoerceValidator} (which receives it as its
|
|
10
|
+
# +options+ argument).
|
|
11
|
+
#
|
|
12
|
+
# All three fields may be +nil+ (e.g. a remountable API evaluated on its
|
|
13
|
+
# base instance has no resolved +type+ yet).
|
|
14
|
+
# +coerce_method+ (not +method+) avoids shadowing +Object#method+.
|
|
15
|
+
CoerceOptions = Data.define(:type, :coerce_method, :message) do
|
|
16
|
+
def initialize(type: nil, coerce_method: nil, message: nil)
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Validations
|
|
5
|
+
class ContractScope
|
|
6
|
+
# Declare the contract to be used for the endpoint's parameters.
|
|
7
|
+
# @param api [API] the API endpoint to modify.
|
|
8
|
+
# @param contract the contract or schema to be used for validation. Optional.
|
|
9
|
+
# @yield a block yielding a new schema class. Optional.
|
|
10
|
+
def initialize(api, contract = nil, &block)
|
|
11
|
+
# When block is passed, the first arg is either schema or nil.
|
|
12
|
+
contract = Dry::Schema.Params(parent: contract, &block) if block
|
|
13
|
+
|
|
14
|
+
if contract.respond_to?(:schema)
|
|
15
|
+
# It's a Dry::Validation::Contract, then.
|
|
16
|
+
contract = contract.new
|
|
17
|
+
key_map = contract.schema.key_map
|
|
18
|
+
else
|
|
19
|
+
# Dry::Schema::Processor, hopefully.
|
|
20
|
+
key_map = contract.key_map
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
api.inheritable_setting.namespace_stackable[:contract_key_map] = key_map
|
|
24
|
+
api.inheritable_setting.namespace_stackable[:validations] = Validators::ContractScopeValidator.new(schema: contract)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Validations
|
|
5
|
+
# Stand-in for the +@api+ object that {ParamsScope} normally writes to.
|
|
6
|
+
# Used when evaluating a single variant block of a +oneof:+ schema so that
|
|
7
|
+
# the variant's validators are captured locally rather than registered on
|
|
8
|
+
# the real API. Exposes only the slice of the API surface that
|
|
9
|
+
# ParamsScope and its helpers touch during definition.
|
|
10
|
+
class OneofCollector
|
|
11
|
+
attr_reader :inheritable_setting
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@inheritable_setting = Grape::Util::InheritableSetting.new
|
|
15
|
+
@inheritable_setting.namespace_inheritable[:do_not_document] = true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def configuration
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validators
|
|
23
|
+
inheritable_setting.namespace_stackable[:validations]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def declared_params
|
|
27
|
+
inheritable_setting.namespace_stackable[:declared_params]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Evaluate +variant_block+ in a fresh +ParamsScope+ backed by a new
|
|
31
|
+
# collector and return the validators that the block registered.
|
|
32
|
+
def self.collect(variant_block)
|
|
33
|
+
collector = new
|
|
34
|
+
ParamsScope.new(api: collector, type: Hash, &variant_block)
|
|
35
|
+
collector.validators
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Validations
|
|
5
|
+
# Holds per-request mutable state that must not live on shared ParamsScope
|
|
6
|
+
# instances. Both trackers are identity-keyed hashes so that ParamsScope
|
|
7
|
+
# objects can serve as keys without relying on value equality.
|
|
8
|
+
#
|
|
9
|
+
# Lifecycle is managed by Endpoint#run_validators via +.track+.
|
|
10
|
+
# Use +.current+ to access the instance for the running request.
|
|
11
|
+
class ParamScopeTracker
|
|
12
|
+
# Fiber-local key used to store the current tracker.
|
|
13
|
+
# Fiber[] (Ruby 3.0+) is used instead of Thread.current[] so that
|
|
14
|
+
# fiber-based servers (e.g. Falcon with async) isolate each request's
|
|
15
|
+
# tracker within its own fiber rather than sharing state across all
|
|
16
|
+
# fibers running on the same thread.
|
|
17
|
+
FIBER_KEY = :grape_param_scope_tracker
|
|
18
|
+
EMPTY_PARAMS = [].freeze
|
|
19
|
+
|
|
20
|
+
def self.track
|
|
21
|
+
previous = Fiber[FIBER_KEY]
|
|
22
|
+
Fiber[FIBER_KEY] = new
|
|
23
|
+
yield
|
|
24
|
+
ensure
|
|
25
|
+
Fiber[FIBER_KEY] = previous
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.current
|
|
29
|
+
Fiber[FIBER_KEY]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def store_index(scope, index)
|
|
33
|
+
index_tracker.store(scope, index)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def index_for(scope)
|
|
37
|
+
index_tracker[scope]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns qualifying params for +scope+, or EMPTY_PARAMS if none were stored.
|
|
41
|
+
# Note: an explicitly stored empty array and "never stored" are treated identically
|
|
42
|
+
# by callers (both yield a blank result that falls through to the parent params).
|
|
43
|
+
def qualifying_params(scope)
|
|
44
|
+
qualifying_params_tracker.fetch(scope, EMPTY_PARAMS)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def store_qualifying_params(scope, params)
|
|
48
|
+
qualifying_params_tracker.store(scope, params)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def index_tracker
|
|
54
|
+
@index_tracker ||= {}.compare_by_identity
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def qualifying_params_tracker
|
|
58
|
+
@qualifying_params_tracker ||= {}.compare_by_identity
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Validations
|
|
5
|
+
# Documents parameters of an endpoint. Reads from a frozen
|
|
6
|
+
# +ValidationsSpec+; never mutates the user's validations hash.
|
|
7
|
+
module ParamsDocumentation
|
|
8
|
+
def document_params(attrs, spec)
|
|
9
|
+
return if @api.inheritable_setting.namespace_inheritable[:do_not_document]
|
|
10
|
+
|
|
11
|
+
documented_attrs = attrs.to_h do |name|
|
|
12
|
+
[full_name(name), extract_details(spec)]
|
|
13
|
+
end
|
|
14
|
+
@api.inheritable_setting.namespace_stackable[:params] = documented_attrs
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def extract_details(spec)
|
|
20
|
+
details = {}
|
|
21
|
+
details[:required] = spec.required?
|
|
22
|
+
details[:type] = TypeCache[spec.coerce_type] if spec.coerce_type
|
|
23
|
+
details[:values] = spec.values if spec.values
|
|
24
|
+
details[:except_values] = spec.except_values if spec.except_values
|
|
25
|
+
details[:default] = spec.default unless spec.default.nil?
|
|
26
|
+
|
|
27
|
+
length = spec.raw[:length]
|
|
28
|
+
if length.is_a?(Hash)
|
|
29
|
+
details[:min_length] = length[:min] if length.key?(:min)
|
|
30
|
+
details[:max_length] = length[:max] if length.key?(:max)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc = spec.raw[:desc] || spec.raw[:description]
|
|
34
|
+
details[:desc] = desc if desc
|
|
35
|
+
|
|
36
|
+
documentation = spec.raw[:documentation]
|
|
37
|
+
details[:documentation] = documentation if documentation
|
|
38
|
+
|
|
39
|
+
details
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class TypeCache < Grape::Util::Cache
|
|
43
|
+
def initialize
|
|
44
|
+
super
|
|
45
|
+
@cache = Hash.new do |h, type|
|
|
46
|
+
h[type] = type.to_s
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|