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/lib/grape/api/helpers.rb
CHANGED
@@ -0,0 +1,283 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'grape/router'
|
4
|
+
|
5
|
+
module Grape
|
6
|
+
class API
|
7
|
+
# The API Instance class, is the engine behind Grape::API. Each class that inherits
|
8
|
+
# from this will represent a different API instance
|
9
|
+
class Instance
|
10
|
+
include Grape::DSL::API
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :instance
|
14
|
+
attr_reader :base
|
15
|
+
attr_accessor :configuration
|
16
|
+
|
17
|
+
def given(conditional_option, &block)
|
18
|
+
evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block_given?
|
19
|
+
end
|
20
|
+
|
21
|
+
def mounted(&block)
|
22
|
+
evaluate_as_instance_with_configuration(block, lazy: true)
|
23
|
+
end
|
24
|
+
|
25
|
+
def base=(grape_api)
|
26
|
+
@base = grape_api
|
27
|
+
grape_api.instances << self
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
(base && base.to_s) || super
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_instance?
|
35
|
+
self == base.base_instance
|
36
|
+
end
|
37
|
+
|
38
|
+
# A class-level lock to ensure the API is not compiled by multiple
|
39
|
+
# threads simultaneously within the same process.
|
40
|
+
LOCK = Mutex.new
|
41
|
+
|
42
|
+
# Clears all defined routes, endpoints, etc., on this API.
|
43
|
+
def reset!
|
44
|
+
reset_endpoints!
|
45
|
+
reset_routes!
|
46
|
+
reset_validations!
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parses the API's definition and compiles it into an instance of
|
50
|
+
# Grape::API.
|
51
|
+
def compile
|
52
|
+
@instance ||= new
|
53
|
+
end
|
54
|
+
|
55
|
+
# Wipe the compiled API so we can recompile after changes were made.
|
56
|
+
def change!
|
57
|
+
@instance = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# This is the interface point between Rack and Grape; it accepts a request
|
61
|
+
# from Rack and ultimately returns an array of three values: the status,
|
62
|
+
# the headers, and the body. See [the rack specification]
|
63
|
+
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
|
64
|
+
def call(env)
|
65
|
+
compile!
|
66
|
+
call!(env)
|
67
|
+
end
|
68
|
+
|
69
|
+
# A non-synchronized version of ::call.
|
70
|
+
def call!(env)
|
71
|
+
instance.call(env)
|
72
|
+
end
|
73
|
+
|
74
|
+
# (see #cascade?)
|
75
|
+
def cascade(value = nil)
|
76
|
+
if value.nil?
|
77
|
+
inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
|
78
|
+
else
|
79
|
+
namespace_inheritable(:cascade, value)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def compile!
|
84
|
+
return if instance
|
85
|
+
LOCK.synchronize { compile unless instance }
|
86
|
+
end
|
87
|
+
|
88
|
+
# see Grape::Router#recognize_path
|
89
|
+
def recognize_path(path)
|
90
|
+
compile!
|
91
|
+
instance.router.recognize_path(path)
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def prepare_routes
|
97
|
+
endpoints.map(&:routes).flatten
|
98
|
+
end
|
99
|
+
|
100
|
+
# Execute first the provided block, then each of the
|
101
|
+
# block passed in. Allows for simple 'before' setups
|
102
|
+
# of settings stack pushes.
|
103
|
+
def nest(*blocks, &block)
|
104
|
+
blocks.reject!(&:nil?)
|
105
|
+
if blocks.any?
|
106
|
+
evaluate_as_instance_with_configuration(block) if block_given?
|
107
|
+
blocks.each { |b| evaluate_as_instance_with_configuration(b) }
|
108
|
+
reset_validations!
|
109
|
+
else
|
110
|
+
instance_eval(&block)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def evaluate_as_instance_with_configuration(block, lazy: false)
|
115
|
+
lazy_block = Grape::Util::LazyBlock.new do |configuration|
|
116
|
+
value_for_configuration = configuration
|
117
|
+
if value_for_configuration.respond_to?(:lazy?) && value_for_configuration.lazy?
|
118
|
+
self.configuration = value_for_configuration.evaluate
|
119
|
+
end
|
120
|
+
response = instance_eval(&block)
|
121
|
+
self.configuration = value_for_configuration
|
122
|
+
response
|
123
|
+
end
|
124
|
+
if base && base_instance? && lazy
|
125
|
+
lazy_block
|
126
|
+
else
|
127
|
+
lazy_block.evaluate_from(configuration)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def inherited(subclass)
|
132
|
+
subclass.reset!
|
133
|
+
subclass.logger = logger.clone
|
134
|
+
end
|
135
|
+
|
136
|
+
def inherit_settings(other_settings)
|
137
|
+
top_level_setting.inherit_from other_settings.point_in_time_copy
|
138
|
+
|
139
|
+
# Propagate any inherited params down to our endpoints, and reset any
|
140
|
+
# compiled routes.
|
141
|
+
endpoints.each do |e|
|
142
|
+
e.inherit_settings(top_level_setting.namespace_stackable)
|
143
|
+
e.reset_routes!
|
144
|
+
end
|
145
|
+
|
146
|
+
reset_routes!
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
attr_reader :router
|
151
|
+
|
152
|
+
# Builds the routes from the defined endpoints, effectively compiling
|
153
|
+
# this API into a usable form.
|
154
|
+
def initialize
|
155
|
+
@router = Router.new
|
156
|
+
add_head_not_allowed_methods_and_options_methods
|
157
|
+
self.class.endpoints.each do |endpoint|
|
158
|
+
endpoint.mount_in(@router)
|
159
|
+
end
|
160
|
+
|
161
|
+
@router.compile!
|
162
|
+
@router.freeze
|
163
|
+
end
|
164
|
+
|
165
|
+
# Handle a request. See Rack documentation for what `env` is.
|
166
|
+
def call(env)
|
167
|
+
result = @router.call(env)
|
168
|
+
result[1].delete(Grape::Http::Headers::X_CASCADE) unless cascade?
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
# Some requests may return a HTTP 404 error if grape cannot find a matching
|
173
|
+
# route. In this case, Grape::Router adds a X-Cascade header to the response
|
174
|
+
# and sets it to 'pass', indicating to grape's parents they should keep
|
175
|
+
# looking for a matching route on other resources.
|
176
|
+
#
|
177
|
+
# In some applications (e.g. mounting grape on rails), one might need to trap
|
178
|
+
# errors from reaching upstream. This is effectivelly done by unsetting
|
179
|
+
# X-Cascade. Default :cascade is true.
|
180
|
+
def cascade?
|
181
|
+
return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade)
|
182
|
+
return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
reset!
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
# For every resource add a 'OPTIONS' route that returns an HTTP 204 response
|
191
|
+
# with a list of HTTP methods that can be called. Also add a route that
|
192
|
+
# will return an HTTP 405 response for any HTTP method that the resource
|
193
|
+
# cannot handle.
|
194
|
+
def add_head_not_allowed_methods_and_options_methods
|
195
|
+
versioned_route_configs = collect_route_config_per_pattern
|
196
|
+
# The paths we collected are prepared (cf. Path#prepare), so they
|
197
|
+
# contain already versioning information when using path versioning.
|
198
|
+
# Disable versioning so adding a route won't prepend versioning
|
199
|
+
# informations again.
|
200
|
+
without_root_prefix do
|
201
|
+
without_versioning do
|
202
|
+
versioned_route_configs.each do |config|
|
203
|
+
allowed_methods = config[:methods].dup
|
204
|
+
|
205
|
+
unless self.class.namespace_inheritable(:do_not_route_head)
|
206
|
+
allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
|
207
|
+
end
|
208
|
+
|
209
|
+
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
|
210
|
+
|
211
|
+
unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
|
212
|
+
config[:endpoint].options[:options_route_enabled] = true
|
213
|
+
end
|
214
|
+
|
215
|
+
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
|
216
|
+
generate_not_allowed_method(config[:pattern], **attributes)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
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
|
+
# Generate a route that returns an HTTP 405 response for a user defined
|
242
|
+
# path on methods not specified
|
243
|
+
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
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
|
251
|
+
return if not_allowed_methods.empty?
|
252
|
+
@router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Allows definition of endpoints that ignore the versioning configuration
|
256
|
+
# used by the rest of your API.
|
257
|
+
def without_versioning(&_block)
|
258
|
+
old_version = self.class.namespace_inheritable(:version)
|
259
|
+
old_version_options = self.class.namespace_inheritable(:version_options)
|
260
|
+
|
261
|
+
self.class.namespace_inheritable_to_nil(:version)
|
262
|
+
self.class.namespace_inheritable_to_nil(:version_options)
|
263
|
+
|
264
|
+
yield
|
265
|
+
|
266
|
+
self.class.namespace_inheritable(:version, old_version)
|
267
|
+
self.class.namespace_inheritable(:version_options, old_version_options)
|
268
|
+
end
|
269
|
+
|
270
|
+
# Allows definition of endpoints that ignore the root prefix used by the
|
271
|
+
# rest of your API.
|
272
|
+
def without_root_prefix(&_block)
|
273
|
+
old_prefix = self.class.namespace_inheritable(:root_prefix)
|
274
|
+
|
275
|
+
self.class.namespace_inheritable_to_nil(:root_prefix)
|
276
|
+
|
277
|
+
yield
|
278
|
+
|
279
|
+
self.class.namespace_inheritable(:root_prefix, old_prefix)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
data/lib/grape/config.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Config
|
5
|
+
class Configuration
|
6
|
+
ATTRIBUTES = %i[
|
7
|
+
param_builder
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
attr_accessor(*ATTRIBUTES)
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
reset
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset
|
17
|
+
self.param_builder = Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.extended(base)
|
22
|
+
def base.configure
|
23
|
+
block_given? ? yield(config) : config
|
24
|
+
end
|
25
|
+
|
26
|
+
def base.config
|
27
|
+
@configuration ||= Grape::Config::Configuration.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Grape.extend Grape::Config
|
34
|
+
Grape.config.reset
|
@@ -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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -43,6 +45,26 @@ module Grape
|
|
43
45
|
def after(&block)
|
44
46
|
namespace_stackable(:afters, block)
|
45
47
|
end
|
48
|
+
|
49
|
+
# Allows you to specify a something that will always be executed after a call
|
50
|
+
# API call. Unlike the `after` block, this code will run even on
|
51
|
+
# unsuccesful requests.
|
52
|
+
# @example
|
53
|
+
# class ExampleAPI < Grape::API
|
54
|
+
# before do
|
55
|
+
# ApiLogger.start
|
56
|
+
# end
|
57
|
+
# finally do
|
58
|
+
# ApiLogger.close
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# This will make sure that the ApiLogger is opened and closed around every
|
63
|
+
# request
|
64
|
+
# @param ensured_block [Proc] The block to be executed after every api_call
|
65
|
+
def finally(&block)
|
66
|
+
namespace_stackable(:finallies, block)
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
48
70
|
end
|
data/lib/grape/dsl/desc.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module DSL
|
3
5
|
module Desc
|
@@ -9,6 +11,7 @@ module Grape
|
|
9
11
|
# @param options [Hash] other properties you can set to describe the
|
10
12
|
# endpoint or namespace. Optional.
|
11
13
|
# @option options :detail [String] additional detail about this endpoint
|
14
|
+
# @option options :summary [String] summary for this endpoint
|
12
15
|
# @option options :params [Hash] param types and info. normally, you set
|
13
16
|
# these via the `params` dsl method.
|
14
17
|
# @option options :entity [Grape::Entity] the entity returned upon a
|
@@ -16,7 +19,16 @@ module Grape
|
|
16
19
|
# @option options :http_codes [Array[Array]] possible HTTP codes this
|
17
20
|
# endpoint may return, with their meanings, in a 2d array
|
18
21
|
# @option options :named [String] a specific name to help find this route
|
22
|
+
# @option options :body_name [String] override the autogenerated body name param
|
19
23
|
# @option options :headers [Hash] HTTP headers this method can accept
|
24
|
+
# @option options :hidden [Boolean] hide the endpoint or not
|
25
|
+
# @option options :deprecated [Boolean] deprecate the endpoint or not
|
26
|
+
# @option options :is_array [Boolean] response entity is array or not
|
27
|
+
# @option options :nickname [String] nickname of the endpoint
|
28
|
+
# @option options :produces [Array[String]] a list of MIME types the endpoint produce
|
29
|
+
# @option options :consumes [Array[String]] a list of MIME types the endpoint consume
|
30
|
+
# @option options :security [Array[Hash]] a list of security schemes
|
31
|
+
# @option options :tags [Array[String]] a list of tags
|
20
32
|
# @yield a block yielding an instance context with methods mapping to
|
21
33
|
# each of the above, except that :entity is also aliased as #success
|
22
34
|
# and :http_codes is aliased as #failure.
|
@@ -39,7 +51,17 @@ module Grape
|
|
39
51
|
#
|
40
52
|
def desc(description, options = {}, &config_block)
|
41
53
|
if block_given?
|
42
|
-
|
54
|
+
endpoint_configuration = if defined?(configuration)
|
55
|
+
# When the instance is mounted - the configuration is executed on mount time
|
56
|
+
if configuration.respond_to?(:evaluate)
|
57
|
+
configuration.evaluate
|
58
|
+
# Within `given` or `mounted blocks` the configuration is already evaluated
|
59
|
+
elsif configuration.is_a?(Hash)
|
60
|
+
configuration
|
61
|
+
end
|
62
|
+
end
|
63
|
+
endpoint_configuration ||= {}
|
64
|
+
config_class = desc_container(endpoint_configuration)
|
43
65
|
|
44
66
|
config_class.configure do
|
45
67
|
description description
|
@@ -59,13 +81,12 @@ module Grape
|
|
59
81
|
end
|
60
82
|
|
61
83
|
def description_field(field, value = nil)
|
84
|
+
description = route_setting(:description)
|
62
85
|
if value
|
63
|
-
description = route_setting(:description)
|
64
86
|
description ||= route_setting(:description, {})
|
65
87
|
description[field] = value
|
66
|
-
|
67
|
-
description
|
68
|
-
description[field] if description
|
88
|
+
elsif description
|
89
|
+
description[field]
|
69
90
|
end
|
70
91
|
end
|
71
92
|
|
@@ -75,17 +96,30 @@ module Grape
|
|
75
96
|
end
|
76
97
|
|
77
98
|
# Returns an object which configures itself via an instance-context DSL.
|
78
|
-
def desc_container
|
99
|
+
def desc_container(endpoint_configuration)
|
79
100
|
Module.new do
|
80
101
|
include Grape::Util::StrictHashConfiguration.module(
|
102
|
+
:summary,
|
81
103
|
:description,
|
82
104
|
:detail,
|
83
105
|
:params,
|
84
106
|
:entity,
|
85
107
|
:http_codes,
|
86
108
|
:named,
|
87
|
-
:
|
109
|
+
:body_name,
|
110
|
+
:headers,
|
111
|
+
:hidden,
|
112
|
+
:deprecated,
|
113
|
+
:is_array,
|
114
|
+
:nickname,
|
115
|
+
:produces,
|
116
|
+
:consumes,
|
117
|
+
:security,
|
118
|
+
:tags
|
88
119
|
)
|
120
|
+
config_context.define_singleton_method(:configuration) do
|
121
|
+
endpoint_configuration
|
122
|
+
end
|
89
123
|
|
90
124
|
def config_context.success(*args)
|
91
125
|
entity(*args)
|