grape 1.2.5 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|