grape 1.1.0 → 1.5.3
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 +278 -44
- data/LICENSE +1 -1
- data/README.md +514 -69
- data/UPGRADING.md +424 -17
- data/grape.gemspec +13 -2
- data/lib/grape.rb +104 -71
- data/lib/grape/api.rb +138 -175
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +283 -0
- data/lib/grape/config.rb +34 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +22 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +41 -7
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +5 -2
- data/lib/grape/dsl/inside_route.rb +92 -49
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +9 -0
- data/lib/grape/dsl/parameters.rb +25 -14
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +17 -10
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +24 -4
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +59 -35
- data/lib/grape/error_formatter.rb +4 -2
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +20 -14
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
- data/lib/grape/exceptions/invalid_formatter.rb +2 -0
- data/lib/grape/exceptions/invalid_message_body.rb +2 -0
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
- data/lib/grape/exceptions/method_not_allowed.rb +2 -0
- data/lib/grape/exceptions/missing_group_type.rb +2 -0
- data/lib/grape/exceptions/missing_mime_type.rb +2 -0
- data/lib/grape/exceptions/missing_option.rb +2 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
- data/lib/grape/exceptions/unknown_options.rb +2 -0
- data/lib/grape/exceptions/unknown_parameter.rb +2 -0
- data/lib/grape/exceptions/unknown_validator.rb +2 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
- data/lib/grape/exceptions/validation.rb +4 -2
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +16 -13
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/formatter/json.rb +2 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -0
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +2 -0
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/locale/en.yml +3 -1
- data/lib/grape/middleware/auth/base.rb +7 -7
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +10 -7
- data/lib/grape/middleware/error.rb +21 -16
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +8 -6
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +12 -0
- data/lib/grape/middleware/stack.rb +13 -3
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +10 -8
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
- data/lib/grape/middleware/versioner/path.rb +3 -1
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser.rb +4 -2
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +19 -10
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +14 -28
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +2 -0
- data/lib/grape/util/inheritable_values.rb +7 -25
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +27 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +98 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +10 -35
- data/lib/grape/util/stackable_values.rb +21 -34
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +16 -6
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +51 -30
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types.rb +13 -38
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +46 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/validator_factory.rb +8 -11
- data/lib/grape/validations/validators/all_or_none.rb +8 -13
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +5 -4
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
- data/lib/grape/validations/validators/base.rb +20 -16
- data/lib/grape/validations/validators/coerce.rb +46 -29
- data/lib/grape/validations/validators/default.rb +6 -6
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
- data/lib/grape/validations/validators/except_values.rb +4 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
- data/lib/grape/validations/validators/presence.rb +3 -1
- data/lib/grape/validations/validators/regexp.rb +4 -2
- data/lib/grape/validations/validators/same_as.rb +26 -0
- data/lib/grape/validations/validators/values.rb +18 -6
- data/lib/grape/version.rb +3 -1
- data/spec/grape/api/custom_validations_spec.rb +5 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
- data/spec/grape/api/inherited_helpers_spec.rb +2 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +473 -0
- data/spec/grape/api_spec.rb +565 -12
- data/spec/grape/config_spec.rb +19 -0
- data/spec/grape/dsl/callbacks_spec.rb +2 -0
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +42 -16
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +4 -2
- data/spec/grape/dsl/inside_route_spec.rb +184 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +10 -0
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +12 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +53 -523
- data/spec/grape/entity_spec.rb +9 -1
- data/spec/grape/exceptions/base_spec.rb +67 -0
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +25 -7
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +10 -0
- data/spec/grape/middleware/error_spec.rb +3 -1
- data/spec/grape/middleware/exception_spec.rb +4 -2
- data/spec/grape/middleware/formatter_spec.rb +33 -16
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +12 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +9 -1
- data/spec/grape/middleware/versioner/param_spec.rb +3 -1
- data/spec/grape/middleware/versioner/path_spec.rb +3 -1
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +21 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +26 -0
- data/spec/grape/util/inheritable_setting_spec.rb +2 -0
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
- data/spec/grape/util/stackable_values_spec.rb +3 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
- data/spec/grape/validations/params_scope_spec.rb +213 -9
- data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
- data/spec/grape/validations/validators/coerce_spec.rb +476 -135
- data/spec/grape/validations/validators/default_spec.rb +172 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
- data/spec/grape/validations/validators/except_values_spec.rb +4 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +65 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +388 -50
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +22 -20
- data/spec/spec_helper.rb +12 -1
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/chunks.rb +14 -0
- data/spec/support/content_type_helpers.rb +2 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +8 -8
- metadata +86 -48
- data/Appraisals +0 -32
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile +0 -35
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_edge.gemfile +0 -35
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
data/grape.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
4
|
require 'grape/version'
|
3
5
|
|
@@ -11,15 +13,24 @@ Gem::Specification.new do |s|
|
|
11
13
|
s.summary = 'A simple Ruby framework for building REST-like APIs.'
|
12
14
|
s.description = 'A Ruby framework for rapid API development with great conventions.'
|
13
15
|
s.license = 'MIT'
|
16
|
+
s.metadata = {
|
17
|
+
'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
|
18
|
+
'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
|
19
|
+
'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
|
20
|
+
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
|
21
|
+
}
|
14
22
|
|
15
23
|
s.add_runtime_dependency 'activesupport'
|
16
24
|
s.add_runtime_dependency 'builder'
|
25
|
+
s.add_runtime_dependency 'dry-types', '>= 1.1'
|
17
26
|
s.add_runtime_dependency 'mustermann-grape', '~> 1.0.0'
|
18
27
|
s.add_runtime_dependency 'rack', '>= 1.3.0'
|
19
28
|
s.add_runtime_dependency 'rack-accept'
|
20
|
-
s.add_runtime_dependency 'virtus', '>= 1.0.0'
|
21
29
|
|
22
|
-
s.files =
|
30
|
+
s.files = %w[CHANGELOG.md CONTRIBUTING.md README.md grape.png UPGRADING.md LICENSE]
|
31
|
+
s.files += %w[grape.gemspec]
|
32
|
+
s.files += Dir['lib/**/*']
|
23
33
|
s.test_files = Dir['spec/**/*']
|
24
34
|
s.require_paths = ['lib']
|
35
|
+
s.required_ruby_version = '>= 2.4.0'
|
25
36
|
end
|
data/lib/grape.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
2
4
|
require 'rack'
|
3
5
|
require 'rack/builder'
|
@@ -10,6 +12,7 @@ require 'active_support/core_ext/hash/indifferent_access'
|
|
10
12
|
require 'active_support/core_ext/object/blank'
|
11
13
|
require 'active_support/core_ext/array/extract_options'
|
12
14
|
require 'active_support/core_ext/array/wrap'
|
15
|
+
require 'active_support/core_ext/array/conversions'
|
13
16
|
require 'active_support/core_ext/hash/deep_merge'
|
14
17
|
require 'active_support/core_ext/hash/reverse_merge'
|
15
18
|
require 'active_support/core_ext/hash/except'
|
@@ -18,9 +21,6 @@ require 'active_support/core_ext/hash/conversions'
|
|
18
21
|
require 'active_support/dependencies/autoload'
|
19
22
|
require 'active_support/notifications'
|
20
23
|
require 'i18n'
|
21
|
-
require 'thread'
|
22
|
-
|
23
|
-
require 'virtus'
|
24
24
|
|
25
25
|
I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
|
26
26
|
|
@@ -34,7 +34,6 @@ module Grape
|
|
34
34
|
autoload :Namespace
|
35
35
|
|
36
36
|
autoload :Path
|
37
|
-
|
38
37
|
autoload :Cookies
|
39
38
|
autoload :Validations
|
40
39
|
autoload :ErrorFormatter
|
@@ -55,105 +54,125 @@ module Grape
|
|
55
54
|
|
56
55
|
module Exceptions
|
57
56
|
extend ::ActiveSupport::Autoload
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
57
|
+
eager_autoload do
|
58
|
+
autoload :Base
|
59
|
+
autoload :Validation
|
60
|
+
autoload :ValidationArrayErrors
|
61
|
+
autoload :ValidationErrors
|
62
|
+
autoload :MissingVendorOption
|
63
|
+
autoload :MissingMimeType
|
64
|
+
autoload :MissingOption
|
65
|
+
autoload :InvalidFormatter
|
66
|
+
autoload :InvalidVersionerOption
|
67
|
+
autoload :UnknownValidator
|
68
|
+
autoload :UnknownOptions
|
69
|
+
autoload :UnknownParameter
|
70
|
+
autoload :InvalidWithOptionForRepresent
|
71
|
+
autoload :IncompatibleOptionValues
|
72
|
+
autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
|
73
|
+
autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
|
74
|
+
autoload :InvalidMessageBody
|
75
|
+
autoload :InvalidAcceptHeader
|
76
|
+
autoload :InvalidVersionHeader
|
77
|
+
autoload :MethodNotAllowed
|
78
|
+
autoload :InvalidResponse
|
79
|
+
autoload :EmptyMessageBody
|
80
|
+
end
|
78
81
|
end
|
79
82
|
|
80
83
|
module Extensions
|
81
84
|
extend ::ActiveSupport::Autoload
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
85
|
+
eager_autoload do
|
86
|
+
autoload :DeepMergeableHash
|
87
|
+
autoload :DeepSymbolizeHash
|
88
|
+
autoload :Hash
|
89
|
+
end
|
88
90
|
module ActiveSupport
|
89
91
|
extend ::ActiveSupport::Autoload
|
90
|
-
|
91
|
-
|
92
|
+
eager_autoload do
|
93
|
+
autoload :HashWithIndifferentAccess
|
94
|
+
end
|
92
95
|
end
|
93
96
|
|
94
97
|
module Hashie
|
95
98
|
extend ::ActiveSupport::Autoload
|
96
|
-
|
97
|
-
|
99
|
+
eager_autoload do
|
100
|
+
autoload :Mash
|
101
|
+
end
|
98
102
|
end
|
99
103
|
end
|
100
104
|
|
101
105
|
module Middleware
|
102
106
|
extend ::ActiveSupport::Autoload
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
eager_autoload do
|
108
|
+
autoload :Base
|
109
|
+
autoload :Versioner
|
110
|
+
autoload :Formatter
|
111
|
+
autoload :Error
|
112
|
+
autoload :Globals
|
113
|
+
autoload :Stack
|
114
|
+
autoload :Helpers
|
115
|
+
end
|
109
116
|
|
110
117
|
module Auth
|
111
118
|
extend ::ActiveSupport::Autoload
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
eager_autoload do
|
120
|
+
autoload :Base
|
121
|
+
autoload :DSL
|
122
|
+
autoload :StrategyInfo
|
123
|
+
autoload :Strategies
|
124
|
+
end
|
116
125
|
end
|
117
126
|
|
118
127
|
module Versioner
|
119
128
|
extend ::ActiveSupport::Autoload
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
129
|
+
eager_autoload do
|
130
|
+
autoload :Path
|
131
|
+
autoload :Header
|
132
|
+
autoload :Param
|
133
|
+
autoload :AcceptVersionHeader
|
134
|
+
end
|
124
135
|
end
|
125
136
|
end
|
126
137
|
|
127
138
|
module Util
|
128
139
|
extend ::ActiveSupport::Autoload
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
140
|
+
eager_autoload do
|
141
|
+
autoload :InheritableValues
|
142
|
+
autoload :StackableValues
|
143
|
+
autoload :ReverseStackableValues
|
144
|
+
autoload :InheritableSetting
|
145
|
+
autoload :StrictHashConfiguration
|
146
|
+
autoload :Registrable
|
147
|
+
end
|
135
148
|
end
|
136
149
|
|
137
150
|
module ErrorFormatter
|
138
151
|
extend ::ActiveSupport::Autoload
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
152
|
+
eager_autoload do
|
153
|
+
autoload :Base
|
154
|
+
autoload :Json
|
155
|
+
autoload :Txt
|
156
|
+
autoload :Xml
|
157
|
+
end
|
143
158
|
end
|
144
159
|
|
145
160
|
module Formatter
|
146
161
|
extend ::ActiveSupport::Autoload
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
162
|
+
eager_autoload do
|
163
|
+
autoload :Json
|
164
|
+
autoload :SerializableHash
|
165
|
+
autoload :Txt
|
166
|
+
autoload :Xml
|
167
|
+
end
|
151
168
|
end
|
152
169
|
|
153
170
|
module Parser
|
154
171
|
extend ::ActiveSupport::Autoload
|
155
|
-
|
156
|
-
|
172
|
+
eager_autoload do
|
173
|
+
autoload :Json
|
174
|
+
autoload :Xml
|
175
|
+
end
|
157
176
|
end
|
158
177
|
|
159
178
|
module DSL
|
@@ -177,26 +196,39 @@ module Grape
|
|
177
196
|
|
178
197
|
class API
|
179
198
|
extend ::ActiveSupport::Autoload
|
180
|
-
|
199
|
+
eager_autoload do
|
200
|
+
autoload :Helpers
|
201
|
+
end
|
181
202
|
end
|
182
203
|
|
183
204
|
module Presenters
|
184
205
|
extend ::ActiveSupport::Autoload
|
185
|
-
|
206
|
+
eager_autoload do
|
207
|
+
autoload :Presenter
|
208
|
+
end
|
186
209
|
end
|
187
210
|
|
188
|
-
module
|
211
|
+
module ServeStream
|
189
212
|
extend ::ActiveSupport::Autoload
|
190
|
-
|
191
|
-
|
192
|
-
|
213
|
+
eager_autoload do
|
214
|
+
autoload :FileBody
|
215
|
+
autoload :SendfileResponse
|
216
|
+
autoload :StreamResponse
|
217
|
+
end
|
193
218
|
end
|
194
219
|
end
|
195
220
|
|
196
|
-
require 'grape/
|
221
|
+
require 'grape/config'
|
222
|
+
require 'grape/content_types'
|
223
|
+
|
224
|
+
require 'grape/util/lazy_value'
|
225
|
+
require 'grape/util/lazy_block'
|
226
|
+
require 'grape/util/endpoint_configuration'
|
197
227
|
|
198
228
|
require 'grape/validations/validators/base'
|
199
229
|
require 'grape/validations/attributes_iterator'
|
230
|
+
require 'grape/validations/single_attribute_iterator'
|
231
|
+
require 'grape/validations/multiple_attributes_iterator'
|
200
232
|
require 'grape/validations/validators/allow_blank'
|
201
233
|
require 'grape/validations/validators/as'
|
202
234
|
require 'grape/validations/validators/at_least_one_of'
|
@@ -206,6 +238,7 @@ require 'grape/validations/validators/exactly_one_of'
|
|
206
238
|
require 'grape/validations/validators/mutual_exclusion'
|
207
239
|
require 'grape/validations/validators/presence'
|
208
240
|
require 'grape/validations/validators/regexp'
|
241
|
+
require 'grape/validations/validators/same_as'
|
209
242
|
require 'grape/validations/validators/values'
|
210
243
|
require 'grape/validations/validators/except_values'
|
211
244
|
require 'grape/validations/params_scope'
|
data/lib/grape/api.rb
CHANGED
@@ -1,233 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'grape/router'
|
4
|
+
require 'grape/api/instance'
|
2
5
|
|
3
6
|
module Grape
|
4
7
|
# The API class is the primary entry point for creating Grape APIs. Users
|
5
8
|
# should subclass this class in order to build an API.
|
6
9
|
class API
|
7
|
-
|
10
|
+
# Class methods that we want to call on the API rather than on the API object
|
11
|
+
NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
|
8
12
|
|
9
13
|
class << self
|
10
|
-
|
14
|
+
attr_accessor :base_instance, :instances
|
11
15
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
16
|
+
# Rather than initializing an object of type Grape::API, create an object of type Instance
|
17
|
+
def new(*args, &block)
|
18
|
+
base_instance.new(*args, &block)
|
19
|
+
end
|
15
20
|
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
# When inherited, will create a list of all instances (times the API was mounted)
|
22
|
+
# It will listen to the setup required to mount that endpoint, and replicate it on any new instance
|
23
|
+
def inherited(api, base_instance_parent = Grape::API::Instance)
|
24
|
+
api.initial_setup(base_instance_parent)
|
25
|
+
api.override_all_methods!
|
26
|
+
make_inheritable(api)
|
21
27
|
end
|
22
28
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
def
|
26
|
-
@
|
29
|
+
# Initialize the instance variables on the remountable class, and the base_instance
|
30
|
+
# an instance that will be used to create the set up but will not be mounted
|
31
|
+
def initial_setup(base_instance_parent)
|
32
|
+
@instances = []
|
33
|
+
@setup = Set.new
|
34
|
+
@base_parent = base_instance_parent
|
35
|
+
@base_instance = mount_instance
|
27
36
|
end
|
28
37
|
|
29
|
-
#
|
30
|
-
def
|
31
|
-
|
38
|
+
# Redefines all methods so that are forwarded to add_setup and be recorded
|
39
|
+
def override_all_methods!
|
40
|
+
(base_instance.methods - NON_OVERRIDABLE).each do |method_override|
|
41
|
+
define_singleton_method(method_override) do |*args, &block|
|
42
|
+
add_setup(method_override, *args, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Configure an API from the outside. If a block is given, it'll pass a
|
48
|
+
# configuration hash to the block which you can use to configure your
|
49
|
+
# API. If no block is given, returns the configuration hash.
|
50
|
+
# The configuration set here is accessible from inside an API with
|
51
|
+
# `configuration` as normal.
|
52
|
+
def configure
|
53
|
+
config = @base_instance.configuration
|
54
|
+
if block_given?
|
55
|
+
yield config
|
56
|
+
self
|
57
|
+
else
|
58
|
+
config
|
59
|
+
end
|
32
60
|
end
|
33
61
|
|
34
62
|
# This is the interface point between Rack and Grape; it accepts a request
|
35
63
|
# from Rack and ultimately returns an array of three values: the status,
|
36
64
|
# the headers, and the body. See [the rack specification]
|
37
65
|
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
|
38
|
-
|
39
|
-
|
40
|
-
call
|
66
|
+
# NOTE: This will only be called on an API directly mounted on RACK
|
67
|
+
def call(*args, &block)
|
68
|
+
instance_for_rack.call(*args, &block)
|
41
69
|
end
|
42
70
|
|
43
|
-
#
|
44
|
-
def
|
45
|
-
|
71
|
+
# Allows an API to itself be inheritable:
|
72
|
+
def make_inheritable(api)
|
73
|
+
# When a child API inherits from a parent API.
|
74
|
+
def api.inherited(child_api)
|
75
|
+
# The instances of the child API inherit from the instances of the parent API
|
76
|
+
Grape::API.inherited(child_api, base_instance)
|
77
|
+
end
|
46
78
|
end
|
47
79
|
|
48
|
-
#
|
49
|
-
def
|
50
|
-
if
|
51
|
-
|
80
|
+
# Alleviates problems with autoloading by tring to search for the constant
|
81
|
+
def const_missing(*args)
|
82
|
+
if base_instance.const_defined?(*args)
|
83
|
+
base_instance.const_get(*args)
|
52
84
|
else
|
53
|
-
|
85
|
+
super
|
54
86
|
end
|
55
87
|
end
|
56
88
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
89
|
+
# The remountable class can have a configuration hash to provide some dynamic class-level variables.
|
90
|
+
# For instance, a description could be done using: `desc configuration[:description]` if it may vary
|
91
|
+
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
92
|
+
# too much, you may actually want to provide a new API rather than remount it.
|
93
|
+
def mount_instance(**opts)
|
94
|
+
instance = Class.new(@base_parent)
|
95
|
+
instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
|
96
|
+
instance.base = self
|
97
|
+
replay_setup_on(instance)
|
98
|
+
instance
|
99
|
+
end
|
100
|
+
|
101
|
+
# Replays the set up to produce an API as defined in this class, can be called
|
102
|
+
# on classes that inherit from Grape::API
|
103
|
+
def replay_setup_on(instance)
|
104
|
+
@setup.each do |setup_step|
|
105
|
+
replay_step_on(instance, setup_step)
|
106
|
+
end
|
61
107
|
end
|
62
108
|
|
63
|
-
|
109
|
+
def respond_to?(method, include_private = false)
|
110
|
+
super(method, include_private) || base_instance.respond_to?(method, include_private)
|
111
|
+
end
|
64
112
|
|
65
|
-
def
|
66
|
-
|
113
|
+
def respond_to_missing?(method, include_private = false)
|
114
|
+
base_instance.respond_to?(method, include_private)
|
67
115
|
end
|
68
116
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
blocks.reject!(&:nil?)
|
74
|
-
if blocks.any?
|
75
|
-
instance_eval(&block) if block_given?
|
76
|
-
blocks.each { |b| instance_eval(&b) }
|
77
|
-
reset_validations!
|
117
|
+
def method_missing(method, *args, &block)
|
118
|
+
# If there's a missing method, it may be defined on the base_instance instead.
|
119
|
+
if respond_to_missing?(method)
|
120
|
+
base_instance.send(method, *args, &block)
|
78
121
|
else
|
79
|
-
|
122
|
+
super
|
80
123
|
end
|
81
124
|
end
|
82
125
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
126
|
+
def compile!
|
127
|
+
require 'grape/eager_load'
|
128
|
+
instance_for_rack.compile! # See API::Instance.compile!
|
86
129
|
end
|
87
130
|
|
88
|
-
|
89
|
-
top_level_setting.inherit_from other_settings.point_in_time_copy
|
131
|
+
private
|
90
132
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
133
|
+
def instance_for_rack
|
134
|
+
if never_mounted?
|
135
|
+
base_instance
|
136
|
+
else
|
137
|
+
mounted_instances.first
|
96
138
|
end
|
97
|
-
|
98
|
-
reset_routes!
|
99
139
|
end
|
100
|
-
end
|
101
|
-
|
102
|
-
attr_reader :router
|
103
140
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
141
|
+
# Adds a new stage to the set up require to get a Grape::API up and running
|
142
|
+
def add_setup(method, *args, &block)
|
143
|
+
setup_step = { method: method, args: args, block: block }
|
144
|
+
@setup += [setup_step]
|
145
|
+
last_response = nil
|
146
|
+
@instances.each do |instance|
|
147
|
+
last_response = replay_step_on(instance, setup_step)
|
148
|
+
end
|
149
|
+
last_response
|
111
150
|
end
|
112
151
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
result
|
122
|
-
end
|
123
|
-
|
124
|
-
# Some requests may return a HTTP 404 error if grape cannot find a matching
|
125
|
-
# route. In this case, Grape::Router adds a X-Cascade header to the response
|
126
|
-
# and sets it to 'pass', indicating to grape's parents they should keep
|
127
|
-
# looking for a matching route on other resources.
|
128
|
-
#
|
129
|
-
# In some applications (e.g. mounting grape on rails), one might need to trap
|
130
|
-
# errors from reaching upstream. This is effectivelly done by unsetting
|
131
|
-
# X-Cascade. Default :cascade is true.
|
132
|
-
def cascade?
|
133
|
-
return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.keys.include?(:cascade)
|
134
|
-
return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
|
135
|
-
true
|
136
|
-
end
|
137
|
-
|
138
|
-
reset!
|
139
|
-
|
140
|
-
private
|
141
|
-
|
142
|
-
# For every resource add a 'OPTIONS' route that returns an HTTP 204 response
|
143
|
-
# with a list of HTTP methods that can be called. Also add a route that
|
144
|
-
# will return an HTTP 405 response for any HTTP method that the resource
|
145
|
-
# cannot handle.
|
146
|
-
def add_head_not_allowed_methods_and_options_methods
|
147
|
-
routes_map = {}
|
148
|
-
|
149
|
-
self.class.endpoints.each do |endpoint|
|
150
|
-
routes = endpoint.routes
|
151
|
-
routes.each do |route|
|
152
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
153
|
-
route_key = route.pattern.to_regexp
|
154
|
-
routes_map[route_key] ||= {}
|
155
|
-
route_settings = routes_map[route_key]
|
156
|
-
route_settings[:pattern] = route.pattern
|
157
|
-
route_settings[:requirements] = route.requirements
|
158
|
-
route_settings[:path] = route.origin
|
159
|
-
route_settings[:methods] ||= []
|
160
|
-
route_settings[:methods] << route.request_method
|
161
|
-
route_settings[:endpoint] = route.app
|
162
|
-
|
163
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
164
|
-
route_settings[:methods] = %w[GET PUT POST DELETE PATCH HEAD OPTIONS] if route_settings[:methods].include?('*')
|
152
|
+
def replay_step_on(instance, setup_step)
|
153
|
+
return if skip_immediate_run?(instance, setup_step[:args])
|
154
|
+
args = evaluate_arguments(instance.configuration, *setup_step[:args])
|
155
|
+
response = instance.send(setup_step[:method], *args, &setup_step[:block])
|
156
|
+
if skip_immediate_run?(instance, [response])
|
157
|
+
response
|
158
|
+
else
|
159
|
+
evaluate_arguments(instance.configuration, response).first
|
165
160
|
end
|
166
161
|
end
|
167
162
|
|
168
|
-
#
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
without_versioning do
|
174
|
-
routes_map.each do |_, config|
|
175
|
-
methods = config[:methods]
|
176
|
-
allowed_methods = methods.dup
|
177
|
-
|
178
|
-
unless self.class.namespace_inheritable(:do_not_route_head)
|
179
|
-
allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
|
180
|
-
end
|
181
|
-
|
182
|
-
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ')
|
163
|
+
# Skips steps that contain arguments to be lazily executed (on re-mount time)
|
164
|
+
def skip_immediate_run?(instance, args)
|
165
|
+
instance.base_instance? &&
|
166
|
+
(any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) })
|
167
|
+
end
|
183
168
|
|
184
|
-
|
185
|
-
|
186
|
-
|
169
|
+
def any_lazy?(args)
|
170
|
+
args.any? { |argument| argument.respond_to?(:lazy?) && argument.lazy? }
|
171
|
+
end
|
187
172
|
|
188
|
-
|
189
|
-
|
173
|
+
def evaluate_arguments(configuration, *args)
|
174
|
+
args.map do |argument|
|
175
|
+
if argument.respond_to?(:lazy?) && argument.lazy?
|
176
|
+
argument.evaluate_from(configuration)
|
177
|
+
elsif argument.is_a?(Hash)
|
178
|
+
argument.transform_values { |value| evaluate_arguments(configuration, value).first }
|
179
|
+
elsif argument.is_a?(Array)
|
180
|
+
evaluate_arguments(configuration, *argument)
|
181
|
+
else
|
182
|
+
argument
|
190
183
|
end
|
191
184
|
end
|
192
185
|
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Generate a route that returns an HTTP 405 response for a user defined
|
196
|
-
# path on methods not specified
|
197
|
-
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
198
|
-
not_allowed_methods = %w[GET PUT POST DELETE PATCH HEAD] - allowed_methods
|
199
|
-
not_allowed_methods << Grape::Http::Headers::OPTIONS if self.class.namespace_inheritable(:do_not_route_options)
|
200
186
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
# Allows definition of endpoints that ignore the versioning configuration
|
207
|
-
# used by the rest of your API.
|
208
|
-
def without_versioning(&_block)
|
209
|
-
old_version = self.class.namespace_inheritable(:version)
|
210
|
-
old_version_options = self.class.namespace_inheritable(:version_options)
|
211
|
-
|
212
|
-
self.class.namespace_inheritable_to_nil(:version)
|
213
|
-
self.class.namespace_inheritable_to_nil(:version_options)
|
214
|
-
|
215
|
-
yield
|
216
|
-
|
217
|
-
self.class.namespace_inheritable(:version, old_version)
|
218
|
-
self.class.namespace_inheritable(:version_options, old_version_options)
|
219
|
-
end
|
220
|
-
|
221
|
-
# Allows definition of endpoints that ignore the root prefix used by the
|
222
|
-
# rest of your API.
|
223
|
-
def without_root_prefix(&_block)
|
224
|
-
old_prefix = self.class.namespace_inheritable(:root_prefix)
|
225
|
-
|
226
|
-
self.class.namespace_inheritable_to_nil(:root_prefix)
|
227
|
-
|
228
|
-
yield
|
187
|
+
def never_mounted?
|
188
|
+
mounted_instances.empty?
|
189
|
+
end
|
229
190
|
|
230
|
-
|
191
|
+
def mounted_instances
|
192
|
+
instances - [base_instance]
|
193
|
+
end
|
231
194
|
end
|
232
195
|
end
|
233
196
|
end
|