grape 1.2.5 → 1.4.0
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 +97 -0
- data/LICENSE +1 -1
- data/README.md +53 -16
- data/UPGRADING.md +231 -23
- data/grape.gemspec +10 -1
- data/lib/grape.rb +6 -7
- data/lib/grape/api.rb +4 -2
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +36 -33
- data/lib/grape/config.rb +2 -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 +2 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +2 -0
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +4 -2
- data/lib/grape/dsl/inside_route.rb +83 -34
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +2 -0
- data/lib/grape/dsl/parameters.rb +8 -6
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +9 -5
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +20 -1
- data/lib/grape/eager_load.rb +3 -1
- data/lib/grape/endpoint.rb +21 -13
- data/lib/grape/error_formatter.rb +3 -1
- 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 +11 -13
- 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 +2 -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 +3 -1
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +13 -12
- 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/middleware/auth/base.rb +2 -0
- 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 +7 -7
- data/lib/grape/middleware/error.rb +3 -1
- 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 +2 -0
- data/lib/grape/middleware/stack.rb +4 -1
- 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 +6 -4
- 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 +3 -1
- data/lib/grape/parser/json.rb +2 -0
- data/lib/grape/parser/xml.rb +2 -0
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +15 -8
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +39 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +12 -26
- 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 +15 -6
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +2 -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 +2 -0
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +2 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +2 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +4 -0
- data/lib/grape/util/stackable_values.rb +10 -20
- 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 +3 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +2 -0
- data/lib/grape/validations/params_scope.rb +27 -14
- data/lib/grape/validations/single_attribute_iterator.rb +13 -2
- data/lib/grape/validations/types.rb +12 -34
- 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 +15 -49
- 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/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 +2 -0
- data/lib/grape/validations/validators/all_or_none.rb +3 -1
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +2 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +3 -1
- data/lib/grape/validations/validators/base.rb +8 -5
- data/lib/grape/validations/validators/coerce.rb +39 -29
- data/lib/grape/validations/validators/default.rb +2 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -2
- data/lib/grape/validations/validators/except_values.rb +3 -1
- data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +3 -1
- 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 +6 -3
- data/lib/grape/validations/validators/values.rb +17 -5
- 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 +5 -3
- 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 +2 -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 +2 -0
- data/spec/grape/api_spec.rb +99 -11
- data/spec/grape/config_spec.rb +2 -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 +2 -0
- 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 +177 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +2 -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 +2 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint_spec.rb +21 -6
- data/spec/grape/entity_spec.rb +2 -0
- data/spec/grape/exceptions/base_spec.rb +3 -1
- 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 +2 -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 +4 -2
- 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 +3 -1
- 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 +2 -0
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +2 -0
- data/spec/grape/middleware/error_spec.rb +2 -0
- data/spec/grape/middleware/exception_spec.rb +3 -1
- data/spec/grape/middleware/formatter_spec.rb +19 -12
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +11 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +3 -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 +2 -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 +2 -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 +2 -0
- data/spec/grape/validations/params_scope_spec.rb +3 -1
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -4
- 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 +2 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +2 -0
- data/spec/grape/validations/validators/coerce_spec.rb +341 -136
- data/spec/grape/validations/validators/default_spec.rb +123 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +14 -12
- data/spec/grape/validations/validators/except_values_spec.rb +3 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +2 -0
- 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 +2 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +91 -33
- 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 +2 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/basic_auth_encode_helpers.rb +2 -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 +4 -2
- metadata +48 -28
- 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/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,17 +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
30
|
s.files = %w[CHANGELOG.md CONTRIBUTING.md README.md grape.png UPGRADING.md LICENSE]
|
23
31
|
s.files += %w[grape.gemspec]
|
24
32
|
s.files += Dir['lib/**/*']
|
25
33
|
s.test_files = Dir['spec/**/*']
|
26
34
|
s.require_paths = ['lib']
|
35
|
+
s.required_ruby_version = '>= 2.4.0'
|
27
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'
|
@@ -18,9 +20,6 @@ require 'active_support/core_ext/hash/conversions'
|
|
18
20
|
require 'active_support/dependencies/autoload'
|
19
21
|
require 'active_support/notifications'
|
20
22
|
require 'i18n'
|
21
|
-
require 'thread'
|
22
|
-
|
23
|
-
require 'virtus'
|
24
23
|
|
25
24
|
I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
|
26
25
|
|
@@ -84,7 +83,6 @@ module Grape
|
|
84
83
|
eager_autoload do
|
85
84
|
autoload :DeepMergeableHash
|
86
85
|
autoload :DeepSymbolizeHash
|
87
|
-
autoload :DeepHashWithIndifferentAccess
|
88
86
|
autoload :Hash
|
89
87
|
end
|
90
88
|
module ActiveSupport
|
@@ -208,18 +206,19 @@ module Grape
|
|
208
206
|
end
|
209
207
|
end
|
210
208
|
|
211
|
-
module
|
209
|
+
module ServeStream
|
212
210
|
extend ::ActiveSupport::Autoload
|
213
211
|
eager_autoload do
|
214
|
-
autoload :FileResponse
|
215
212
|
autoload :FileBody
|
216
213
|
autoload :SendfileResponse
|
214
|
+
autoload :StreamResponse
|
217
215
|
end
|
218
216
|
end
|
219
217
|
end
|
220
218
|
|
221
219
|
require 'grape/config'
|
222
|
-
require 'grape/
|
220
|
+
require 'grape/content_types'
|
221
|
+
|
223
222
|
require 'grape/util/lazy_value'
|
224
223
|
require 'grape/util/lazy_block'
|
225
224
|
require 'grape/util/endpoint_configuration'
|
data/lib/grape/api.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'grape/router'
|
2
4
|
require 'grape/api/instance'
|
3
5
|
|
@@ -6,7 +8,7 @@ module Grape
|
|
6
8
|
# should subclass this class in order to build an API.
|
7
9
|
class API
|
8
10
|
# Class methods that we want to call on the API rather than on the API object
|
9
|
-
NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile!]).freeze
|
11
|
+
NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
|
10
12
|
|
11
13
|
class << self
|
12
14
|
attr_accessor :base_instance, :instances
|
@@ -173,7 +175,7 @@ module Grape
|
|
173
175
|
if argument.respond_to?(:lazy?) && argument.lazy?
|
174
176
|
argument.evaluate_from(configuration)
|
175
177
|
elsif argument.is_a?(Hash)
|
176
|
-
argument.
|
178
|
+
argument.transform_values { |value| evaluate_arguments(configuration, value).first }
|
177
179
|
elsif argument.is_a?(Array)
|
178
180
|
evaluate_arguments(configuration, *argument)
|
179
181
|
else
|
data/lib/grape/api/helpers.rb
CHANGED
data/lib/grape/api/instance.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'grape/router'
|
2
4
|
|
3
5
|
module Grape
|
@@ -72,7 +74,7 @@ module Grape
|
|
72
74
|
# (see #cascade?)
|
73
75
|
def cascade(value = nil)
|
74
76
|
if value.nil?
|
75
|
-
inheritable_setting.namespace_inheritable.
|
77
|
+
inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
|
76
78
|
else
|
77
79
|
namespace_inheritable(:cascade, value)
|
78
80
|
end
|
@@ -119,7 +121,7 @@ module Grape
|
|
119
121
|
self.configuration = value_for_configuration
|
120
122
|
response
|
121
123
|
end
|
122
|
-
if base_instance? && lazy
|
124
|
+
if base && base_instance? && lazy
|
123
125
|
lazy_block
|
124
126
|
else
|
125
127
|
lazy_block.evaluate_from(configuration)
|
@@ -176,7 +178,7 @@ module Grape
|
|
176
178
|
# errors from reaching upstream. This is effectivelly done by unsetting
|
177
179
|
# X-Cascade. Default :cascade is true.
|
178
180
|
def cascade?
|
179
|
-
return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.
|
181
|
+
return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade)
|
180
182
|
return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
|
181
183
|
true
|
182
184
|
end
|
@@ -190,62 +192,63 @@ module Grape
|
|
190
192
|
# will return an HTTP 405 response for any HTTP method that the resource
|
191
193
|
# cannot handle.
|
192
194
|
def add_head_not_allowed_methods_and_options_methods
|
193
|
-
|
194
|
-
|
195
|
-
self.class.endpoints.each do |endpoint|
|
196
|
-
routes = endpoint.routes
|
197
|
-
routes.each do |route|
|
198
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
199
|
-
route_key = route.pattern.to_regexp
|
200
|
-
routes_map[route_key] ||= {}
|
201
|
-
route_settings = routes_map[route_key]
|
202
|
-
route_settings[:pattern] = route.pattern
|
203
|
-
route_settings[:requirements] = route.requirements
|
204
|
-
route_settings[:path] = route.origin
|
205
|
-
route_settings[:methods] ||= []
|
206
|
-
route_settings[:methods] << route.request_method
|
207
|
-
route_settings[:endpoint] = route.app
|
208
|
-
|
209
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
210
|
-
route_settings[:methods] = %w[GET PUT POST DELETE PATCH HEAD OPTIONS] if route_settings[:methods].include?('*')
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
195
|
+
versioned_route_configs = collect_route_config_per_pattern
|
214
196
|
# The paths we collected are prepared (cf. Path#prepare), so they
|
215
197
|
# contain already versioning information when using path versioning.
|
216
198
|
# Disable versioning so adding a route won't prepend versioning
|
217
199
|
# informations again.
|
218
200
|
without_root_prefix do
|
219
201
|
without_versioning do
|
220
|
-
|
221
|
-
|
222
|
-
allowed_methods = methods.dup
|
202
|
+
versioned_route_configs.each do |config|
|
203
|
+
allowed_methods = config[:methods].dup
|
223
204
|
|
224
205
|
unless self.class.namespace_inheritable(:do_not_route_head)
|
225
206
|
allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
|
226
207
|
end
|
227
208
|
|
228
|
-
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
|
209
|
+
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
|
229
210
|
|
230
211
|
unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
|
231
212
|
config[:endpoint].options[:options_route_enabled] = true
|
232
213
|
end
|
233
214
|
|
234
215
|
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
|
235
|
-
generate_not_allowed_method(config[:pattern], attributes)
|
216
|
+
generate_not_allowed_method(config[:pattern], **attributes)
|
236
217
|
end
|
237
218
|
end
|
238
219
|
end
|
239
220
|
end
|
240
221
|
|
222
|
+
def collect_route_config_per_pattern
|
223
|
+
all_routes = self.class.endpoints.map(&:routes).flatten
|
224
|
+
routes_by_regexp = all_routes.group_by { |route| route.pattern.to_regexp }
|
225
|
+
|
226
|
+
# Build the configuration based on the first endpoint and the collection of methods supported.
|
227
|
+
routes_by_regexp.values.map do |routes|
|
228
|
+
last_route = routes.last # Most of the configuration is taken from the last endpoint
|
229
|
+
matching_wildchar = routes.any? { |route| route.request_method == '*' }
|
230
|
+
{
|
231
|
+
options: {},
|
232
|
+
pattern: last_route.pattern,
|
233
|
+
requirements: last_route.requirements,
|
234
|
+
path: last_route.origin,
|
235
|
+
endpoint: last_route.app,
|
236
|
+
methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method)
|
237
|
+
}
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
241
|
# Generate a route that returns an HTTP 405 response for a user defined
|
242
242
|
# path on methods not specified
|
243
243
|
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
244
|
-
|
245
|
-
|
246
|
-
|
244
|
+
supported_methods =
|
245
|
+
if self.class.namespace_inheritable(:do_not_route_options)
|
246
|
+
Grape::Http::Headers::SUPPORTED_METHODS
|
247
|
+
else
|
248
|
+
Grape::Http::Headers::SUPPORTED_METHODS_WITHOUT_OPTIONS
|
249
|
+
end
|
250
|
+
not_allowed_methods = supported_methods - allowed_methods
|
247
251
|
return if not_allowed_methods.empty?
|
248
|
-
|
249
252
|
@router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
|
250
253
|
end
|
251
254
|
|
data/lib/grape/config.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'grape/util/registrable'
|
4
|
+
|
5
|
+
module Grape
|
6
|
+
module ContentTypes
|
7
|
+
extend Util::Registrable
|
8
|
+
|
9
|
+
# Content types are listed in order of preference.
|
10
|
+
CONTENT_TYPES = {
|
11
|
+
xml: 'application/xml',
|
12
|
+
serializable_hash: 'application/json',
|
13
|
+
json: 'application/json',
|
14
|
+
binary: 'application/octet-stream',
|
15
|
+
txt: 'text/plain'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def content_types_for_settings(settings)
|
20
|
+
return if settings.blank?
|
21
|
+
|
22
|
+
settings.each_with_object({}) { |value, result| result.merge!(value) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def content_types_for(from_settings)
|
26
|
+
if from_settings.present?
|
27
|
+
from_settings
|
28
|
+
else
|
29
|
+
Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/grape/cookies.rb
CHANGED
data/lib/grape/dsl/api.rb
CHANGED
data/lib/grape/dsl/callbacks.rb
CHANGED
data/lib/grape/dsl/desc.rb
CHANGED
data/lib/grape/dsl/headers.rb
CHANGED
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -65,7 +67,7 @@ module Grape
|
|
65
67
|
|
66
68
|
def define_boolean_in_mod(mod)
|
67
69
|
return if defined? mod::Boolean
|
68
|
-
mod.const_set('Boolean',
|
70
|
+
mod.const_set('Boolean', Grape::API::Boolean)
|
69
71
|
end
|
70
72
|
|
71
73
|
def inject_api_helpers_to_mod(mod, &_block)
|
@@ -92,7 +94,7 @@ module Grape
|
|
92
94
|
protected
|
93
95
|
|
94
96
|
def process_named_params
|
95
|
-
return unless @named_params && @named_params.any?
|
97
|
+
return unless instance_variable_defined?(:@named_params) && @named_params && @named_params.any?
|
96
98
|
api.namespace_stackable(:named_params, @named_params)
|
97
99
|
end
|
98
100
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
require 'grape/dsl/headers'
|
3
5
|
|
@@ -26,36 +28,38 @@ module Grape
|
|
26
28
|
# Methods which should not be available in filters until the before filter
|
27
29
|
# has completed
|
28
30
|
module PostBeforeFilter
|
29
|
-
def declared(passed_params, options = {}, declared_params = nil)
|
31
|
+
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
|
30
32
|
options = options.reverse_merge(include_missing: true, include_parent_namespaces: true)
|
31
|
-
declared_params ||= optioned_declared_params(options)
|
33
|
+
declared_params ||= optioned_declared_params(**options)
|
32
34
|
|
33
35
|
if passed_params.is_a?(Array)
|
34
|
-
declared_array(passed_params, options, declared_params)
|
36
|
+
declared_array(passed_params, options, declared_params, params_nested_path)
|
35
37
|
else
|
36
|
-
declared_hash(passed_params, options, declared_params)
|
38
|
+
declared_hash(passed_params, options, declared_params, params_nested_path)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
42
|
private
|
41
43
|
|
42
|
-
def declared_array(passed_params, options, declared_params)
|
44
|
+
def declared_array(passed_params, options, declared_params, params_nested_path)
|
43
45
|
passed_params.map do |passed_param|
|
44
|
-
declared(passed_param || {}, options, declared_params)
|
46
|
+
declared(passed_param || {}, options, declared_params, params_nested_path)
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
|
-
def declared_hash(passed_params, options, declared_params)
|
50
|
+
def declared_hash(passed_params, options, declared_params, params_nested_path)
|
49
51
|
declared_params.each_with_object(passed_params.class.new) do |declared_param, memo|
|
50
52
|
if declared_param.is_a?(Hash)
|
51
53
|
declared_param.each_pair do |declared_parent_param, declared_children_params|
|
54
|
+
params_nested_path_dup = params_nested_path.dup
|
55
|
+
params_nested_path_dup << declared_parent_param.to_s
|
52
56
|
next unless options[:include_missing] || passed_params.key?(declared_parent_param)
|
53
57
|
|
54
58
|
passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
|
55
59
|
memo_key = optioned_param_key(declared_parent_param, options)
|
56
60
|
|
57
|
-
memo[memo_key] = handle_passed_param(
|
58
|
-
declared(passed_children_params, options, declared_children_params)
|
61
|
+
memo[memo_key] = handle_passed_param(passed_children_params, params_nested_path_dup) do
|
62
|
+
declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
|
59
63
|
end
|
60
64
|
end
|
61
65
|
else
|
@@ -75,16 +79,32 @@ module Grape
|
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
def handle_passed_param(
|
79
|
-
|
82
|
+
def handle_passed_param(passed_children_params, params_nested_path, &_block)
|
83
|
+
if should_be_empty_hash?(passed_children_params, params_nested_path)
|
84
|
+
{}
|
85
|
+
elsif should_be_empty_array?(passed_children_params, params_nested_path)
|
86
|
+
[]
|
87
|
+
else
|
88
|
+
yield
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def should_be_empty_array?(passed_children_params, params_nested_path)
|
93
|
+
passed_children_params.empty? && declared_param_is_array?(params_nested_path)
|
80
94
|
end
|
81
95
|
|
82
|
-
def
|
83
|
-
|
96
|
+
def declared_param_is_array?(params_nested_path)
|
97
|
+
key = route_options_params_key(params_nested_path)
|
98
|
+
route_options_params[key] && route_options_params[key][:type] == 'Array'
|
84
99
|
end
|
85
100
|
|
86
|
-
def
|
87
|
-
|
101
|
+
def should_be_empty_hash?(passed_children_params, params_nested_path)
|
102
|
+
passed_children_params.empty? && declared_param_is_hash?(params_nested_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
def declared_param_is_hash?(params_nested_path)
|
106
|
+
key = route_options_params_key(params_nested_path)
|
107
|
+
route_options_params[key] && route_options_params[key][:type] == 'Hash'
|
88
108
|
end
|
89
109
|
|
90
110
|
def route_options_params
|
@@ -95,13 +115,19 @@ module Grape
|
|
95
115
|
options[:stringify] ? declared_param.to_s : declared_param.to_sym
|
96
116
|
end
|
97
117
|
|
98
|
-
def
|
118
|
+
def route_options_params_key(params_nested_path)
|
119
|
+
key = params_nested_path[0]
|
120
|
+
key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
|
121
|
+
key
|
122
|
+
end
|
123
|
+
|
124
|
+
def optioned_declared_params(**options)
|
99
125
|
declared_params = if options[:include_parent_namespaces]
|
100
126
|
# Declared params including parent namespaces
|
101
|
-
route_setting(:
|
127
|
+
route_setting(:declared_params)
|
102
128
|
else
|
103
129
|
# Declared params at current namespace
|
104
|
-
|
130
|
+
namespace_stackable(:declared_params).last || []
|
105
131
|
end
|
106
132
|
|
107
133
|
raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
|
@@ -174,17 +200,17 @@ module Grape
|
|
174
200
|
def status(status = nil)
|
175
201
|
case status
|
176
202
|
when Symbol
|
177
|
-
raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.
|
203
|
+
raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(status)
|
178
204
|
@status = Rack::Utils.status_code(status)
|
179
205
|
when Integer
|
180
206
|
@status = status
|
181
207
|
when nil
|
182
|
-
return @status if @status
|
208
|
+
return @status if instance_variable_defined?(:@status) && @status
|
183
209
|
case request.request_method.to_s.upcase
|
184
210
|
when Grape::Http::Headers::POST
|
185
211
|
201
|
186
212
|
when Grape::Http::Headers::DELETE
|
187
|
-
if @body.present?
|
213
|
+
if instance_variable_defined?(:@body) && @body.present?
|
188
214
|
200
|
189
215
|
else
|
190
216
|
204
|
@@ -235,7 +261,7 @@ module Grape
|
|
235
261
|
@body = ''
|
236
262
|
status 204
|
237
263
|
else
|
238
|
-
@body
|
264
|
+
instance_variable_defined?(:@body) ? @body : nil
|
239
265
|
end
|
240
266
|
end
|
241
267
|
|
@@ -253,23 +279,36 @@ module Grape
|
|
253
279
|
body false
|
254
280
|
end
|
255
281
|
|
256
|
-
#
|
282
|
+
# Deprecated method to send files to the client. Use `sendfile` or `stream`
|
283
|
+
def file(value = nil)
|
284
|
+
if value.is_a?(String)
|
285
|
+
warn '[DEPRECATION] Use sendfile or stream to send files.'
|
286
|
+
sendfile(value)
|
287
|
+
elsif !value.is_a?(NilClass)
|
288
|
+
warn '[DEPRECATION] Use stream to use a Stream object.'
|
289
|
+
stream(value)
|
290
|
+
else
|
291
|
+
warn '[DEPRECATION] Use sendfile or stream to send files.'
|
292
|
+
sendfile
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Allows you to send a file to the client via sendfile.
|
257
297
|
#
|
258
298
|
# @example
|
259
299
|
# get '/file' do
|
260
|
-
#
|
300
|
+
# sendfile FileStreamer.new(...)
|
261
301
|
# end
|
262
302
|
#
|
263
303
|
# GET /file # => "contents of file"
|
264
|
-
def
|
304
|
+
def sendfile(value = nil)
|
265
305
|
if value.is_a?(String)
|
266
|
-
file_body = Grape::
|
267
|
-
@
|
306
|
+
file_body = Grape::ServeStream::FileBody.new(value)
|
307
|
+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
|
268
308
|
elsif !value.is_a?(NilClass)
|
269
|
-
|
270
|
-
@file = Grape::ServeFile::FileResponse.new(value)
|
309
|
+
raise ArgumentError, 'Argument must be a file path'
|
271
310
|
else
|
272
|
-
|
311
|
+
stream
|
273
312
|
end
|
274
313
|
end
|
275
314
|
|
@@ -292,7 +331,16 @@ module Grape
|
|
292
331
|
header 'Content-Length', nil
|
293
332
|
header 'Transfer-Encoding', nil
|
294
333
|
header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
|
295
|
-
|
334
|
+
if value.is_a?(String)
|
335
|
+
file_body = Grape::ServeStream::FileBody.new(value)
|
336
|
+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
|
337
|
+
elsif value.respond_to?(:each)
|
338
|
+
@stream = Grape::ServeStream::StreamResponse.new(value)
|
339
|
+
elsif !value.is_a?(NilClass)
|
340
|
+
raise ArgumentError, 'Stream object must respond to :each.'
|
341
|
+
else
|
342
|
+
instance_variable_defined?(:@stream) ? @stream : nil
|
343
|
+
end
|
296
344
|
end
|
297
345
|
|
298
346
|
# Allows you to make use of Grape Entities by setting
|
@@ -328,11 +376,12 @@ module Grape
|
|
328
376
|
end
|
329
377
|
|
330
378
|
representation = { root => representation } if root
|
379
|
+
|
331
380
|
if key
|
332
|
-
representation = (
|
333
|
-
elsif entity_class.present? &&
|
381
|
+
representation = (body || {}).merge(key => representation)
|
382
|
+
elsif entity_class.present? && body
|
334
383
|
raise ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge)
|
335
|
-
representation =
|
384
|
+
representation = body.merge(representation)
|
336
385
|
end
|
337
386
|
|
338
387
|
body representation
|