grape 0.1.1 → 2.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.
Files changed (197) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1167 -0
  3. data/CONTRIBUTING.md +156 -0
  4. data/LICENSE +1 -1
  5. data/README.md +4192 -0
  6. data/UPGRADING.md +1697 -0
  7. data/grape.gemspec +28 -105
  8. data/grape.png +0 -0
  9. data/lib/grape/api/helpers.rb +9 -0
  10. data/lib/grape/api/instance.rb +247 -0
  11. data/lib/grape/api.rb +158 -194
  12. data/lib/grape/content_types.rb +31 -0
  13. data/lib/grape/cookies.rb +50 -0
  14. data/lib/grape/dry_types.rb +10 -0
  15. data/lib/grape/dsl/api.rb +17 -0
  16. data/lib/grape/dsl/callbacks.rb +69 -0
  17. data/lib/grape/dsl/configuration.rb +15 -0
  18. data/lib/grape/dsl/desc.rb +124 -0
  19. data/lib/grape/dsl/headers.rb +21 -0
  20. data/lib/grape/dsl/helpers.rb +108 -0
  21. data/lib/grape/dsl/inside_route.rb +454 -0
  22. data/lib/grape/dsl/logger.rb +22 -0
  23. data/lib/grape/dsl/middleware.rb +54 -0
  24. data/lib/grape/dsl/parameters.rb +266 -0
  25. data/lib/grape/dsl/request_response.rb +171 -0
  26. data/lib/grape/dsl/routing.rb +248 -0
  27. data/lib/grape/dsl/settings.rb +179 -0
  28. data/lib/grape/dsl/validations.rb +57 -0
  29. data/lib/grape/endpoint.rb +398 -68
  30. data/lib/grape/env.rb +20 -0
  31. data/lib/grape/error_formatter/base.rb +68 -0
  32. data/lib/grape/error_formatter/json.rb +28 -0
  33. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  34. data/lib/grape/error_formatter/txt.rb +21 -0
  35. data/lib/grape/error_formatter/xml.rb +11 -0
  36. data/lib/grape/error_formatter.rb +15 -0
  37. data/lib/grape/exceptions/base.rb +76 -0
  38. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  39. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  40. data/lib/grape/exceptions/incompatible_option_values.rb +11 -0
  41. data/lib/grape/exceptions/invalid_accept_header.rb +11 -0
  42. data/lib/grape/exceptions/invalid_formatter.rb +11 -0
  43. data/lib/grape/exceptions/invalid_message_body.rb +11 -0
  44. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  45. data/lib/grape/exceptions/invalid_response.rb +11 -0
  46. data/lib/grape/exceptions/invalid_version_header.rb +11 -0
  47. data/lib/grape/exceptions/invalid_versioner_option.rb +11 -0
  48. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +11 -0
  49. data/lib/grape/exceptions/method_not_allowed.rb +11 -0
  50. data/lib/grape/exceptions/missing_group_type.rb +13 -0
  51. data/lib/grape/exceptions/missing_mime_type.rb +11 -0
  52. data/lib/grape/exceptions/missing_option.rb +11 -0
  53. data/lib/grape/exceptions/missing_vendor_option.rb +11 -0
  54. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  55. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  56. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  57. data/lib/grape/exceptions/unknown_options.rb +11 -0
  58. data/lib/grape/exceptions/unknown_parameter.rb +11 -0
  59. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  60. data/lib/grape/exceptions/unknown_validator.rb +11 -0
  61. data/lib/grape/exceptions/unsupported_group_type.rb +13 -0
  62. data/lib/grape/exceptions/validation.rb +25 -0
  63. data/lib/grape/exceptions/validation_array_errors.rb +14 -0
  64. data/lib/grape/exceptions/validation_errors.rb +53 -0
  65. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +24 -0
  66. data/lib/grape/extensions/hash.rb +27 -0
  67. data/lib/grape/extensions/hashie/mash.rb +24 -0
  68. data/lib/grape/formatter/base.rb +16 -0
  69. data/lib/grape/formatter/json.rb +13 -0
  70. data/lib/grape/formatter/serializable_hash.rb +39 -0
  71. data/lib/grape/formatter/txt.rb +11 -0
  72. data/lib/grape/formatter/xml.rb +13 -0
  73. data/lib/grape/formatter.rb +17 -0
  74. data/lib/grape/json.rb +10 -0
  75. data/lib/grape/locale/en.yml +59 -0
  76. data/lib/grape/middleware/auth/base.rb +23 -0
  77. data/lib/grape/middleware/auth/dsl.rb +39 -0
  78. data/lib/grape/middleware/auth/strategies.rb +25 -0
  79. data/lib/grape/middleware/auth/strategy_info.rb +15 -0
  80. data/lib/grape/middleware/base.rb +89 -18
  81. data/lib/grape/middleware/error.rb +129 -10
  82. data/lib/grape/middleware/filter.rb +19 -0
  83. data/lib/grape/middleware/formatter.rb +124 -82
  84. data/lib/grape/middleware/globals.rb +14 -0
  85. data/lib/grape/middleware/stack.rb +109 -0
  86. data/lib/grape/middleware/versioner/accept_version_header.rb +38 -0
  87. data/lib/grape/middleware/versioner/base.rb +74 -0
  88. data/lib/grape/middleware/versioner/header.rb +127 -0
  89. data/lib/grape/middleware/versioner/param.rb +32 -0
  90. data/lib/grape/middleware/versioner/path.rb +40 -0
  91. data/lib/grape/middleware/versioner.rb +21 -21
  92. data/lib/grape/namespace.rb +46 -0
  93. data/lib/grape/params_builder/base.rb +18 -0
  94. data/lib/grape/params_builder/hash.rb +11 -0
  95. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  96. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  97. data/lib/grape/params_builder.rb +32 -0
  98. data/lib/grape/parser/base.rb +16 -0
  99. data/lib/grape/parser/json.rb +14 -0
  100. data/lib/grape/parser/xml.rb +14 -0
  101. data/lib/grape/parser.rb +15 -0
  102. data/lib/grape/path.rb +76 -0
  103. data/lib/grape/presenters/presenter.rb +11 -0
  104. data/lib/grape/railtie.rb +9 -0
  105. data/lib/grape/request.rb +190 -0
  106. data/lib/grape/router/base_route.rb +39 -0
  107. data/lib/grape/router/greedy_route.rb +20 -0
  108. data/lib/grape/router/pattern.rb +81 -0
  109. data/lib/grape/router/route.rb +62 -0
  110. data/lib/grape/router.rb +190 -0
  111. data/lib/grape/serve_stream/file_body.rb +36 -0
  112. data/lib/grape/serve_stream/sendfile_response.rb +21 -0
  113. data/lib/grape/serve_stream/stream_response.rb +23 -0
  114. data/lib/grape/types/invalid_value.rb +8 -0
  115. data/lib/grape/util/base_inheritable.rb +43 -0
  116. data/lib/grape/util/cache.rb +17 -0
  117. data/lib/grape/util/endpoint_configuration.rb +8 -0
  118. data/lib/grape/util/header.rb +13 -0
  119. data/lib/grape/util/inheritable_setting.rb +100 -0
  120. data/lib/grape/util/inheritable_values.rb +29 -0
  121. data/lib/grape/util/lazy/block.rb +29 -0
  122. data/lib/grape/util/lazy/value.rb +38 -0
  123. data/lib/grape/util/lazy/value_array.rb +21 -0
  124. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  125. data/lib/grape/util/lazy/value_hash.rb +21 -0
  126. data/lib/grape/util/media_type.rb +70 -0
  127. data/lib/grape/util/registry.rb +27 -0
  128. data/lib/grape/util/reverse_stackable_values.rb +15 -0
  129. data/lib/grape/util/stackable_values.rb +36 -0
  130. data/lib/grape/util/strict_hash_configuration.rb +108 -0
  131. data/lib/grape/validations/attributes_doc.rb +60 -0
  132. data/lib/grape/validations/attributes_iterator.rb +62 -0
  133. data/lib/grape/validations/contract_scope.rb +34 -0
  134. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  135. data/lib/grape/validations/params_scope.rb +538 -0
  136. data/lib/grape/validations/single_attribute_iterator.rb +26 -0
  137. data/lib/grape/validations/types/array_coercer.rb +61 -0
  138. data/lib/grape/validations/types/custom_type_coercer.rb +164 -0
  139. data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
  140. data/lib/grape/validations/types/dry_type_coercer.rb +66 -0
  141. data/lib/grape/validations/types/file.rb +31 -0
  142. data/lib/grape/validations/types/invalid_value.rb +17 -0
  143. data/lib/grape/validations/types/json.rb +71 -0
  144. data/lib/grape/validations/types/multiple_type_coercer.rb +57 -0
  145. data/lib/grape/validations/types/primitive_coercer.rb +73 -0
  146. data/lib/grape/validations/types/set_coercer.rb +35 -0
  147. data/lib/grape/validations/types/variant_collection_coercer.rb +51 -0
  148. data/lib/grape/validations/types.rb +213 -0
  149. data/lib/grape/validations/validator_factory.rb +15 -0
  150. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  151. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  152. data/lib/grape/validations/validators/as_validator.rb +14 -0
  153. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  154. data/lib/grape/validations/validators/base.rb +88 -0
  155. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  156. data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
  157. data/lib/grape/validations/validators/default_validator.rb +37 -0
  158. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  159. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  160. data/lib/grape/validations/validators/length_validator.rb +49 -0
  161. data/lib/grape/validations/validators/multiple_params_base.rb +34 -0
  162. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  163. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  164. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  165. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  166. data/lib/grape/validations/validators/values_validator.rb +60 -0
  167. data/lib/grape/validations.rb +21 -0
  168. data/lib/grape/version.rb +6 -0
  169. data/lib/grape/xml.rb +10 -0
  170. data/lib/grape.rb +81 -17
  171. metadata +250 -192
  172. data/.document +0 -5
  173. data/.gitignore +0 -23
  174. data/.rspec +0 -2
  175. data/.rvmrc +0 -1
  176. data/Gemfile +0 -21
  177. data/Gemfile.lock +0 -58
  178. data/README.markdown +0 -75
  179. data/Rakefile +0 -70
  180. data/VERSION +0 -1
  181. data/autotest/discover.rb +0 -1
  182. data/lib/grape/middleware/auth/basic.rb +0 -30
  183. data/lib/grape/middleware/auth/oauth2.rb +0 -55
  184. data/lib/grape/middleware/prefixer.rb +0 -21
  185. data/lib/grape/middleware_stack.rb +0 -35
  186. data/spec/grape/api_spec.rb +0 -343
  187. data/spec/grape/endpoint_spec.rb +0 -104
  188. data/spec/grape/middleware/auth/basic_spec.rb +0 -31
  189. data/spec/grape/middleware/auth/oauth2_spec.rb +0 -88
  190. data/spec/grape/middleware/base_spec.rb +0 -63
  191. data/spec/grape/middleware/error_spec.rb +0 -49
  192. data/spec/grape/middleware/formatter_spec.rb +0 -87
  193. data/spec/grape/middleware/prefixer_spec.rb +0 -30
  194. data/spec/grape/middleware/versioner_spec.rb +0 -40
  195. data/spec/grape/middleware_stack_spec.rb +0 -47
  196. data/spec/grape_spec.rb +0 -1
  197. data/spec/spec_helper.rb +0 -20
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module DSL
5
+ module Logger
6
+ include Grape::DSL::Settings
7
+
8
+ attr_writer :logger
9
+
10
+ # Set or retrive the configured logger. If none was configured, this
11
+ # method will create a new one, logging to stdout.
12
+ # @param logger [Object] the new logger to use
13
+ def logger(logger = nil)
14
+ if logger
15
+ global_setting(:logger, logger)
16
+ else
17
+ global_setting(:logger) || global_setting(:logger, ::Logger.new($stdout))
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module DSL
5
+ module Middleware
6
+ extend ActiveSupport::Concern
7
+
8
+ include Grape::DSL::Configuration
9
+
10
+ module ClassMethods
11
+ # Apply a custom middleware to the API. Applies
12
+ # to the current namespace and any children, but
13
+ # not parents.
14
+ #
15
+ # @param middleware_class [Class] The class of the middleware you'd like
16
+ # to inject.
17
+ def use(middleware_class, *args, &block)
18
+ arr = [:use, middleware_class, *args]
19
+ arr << block if block
20
+
21
+ namespace_stackable(:middleware, arr)
22
+ end
23
+
24
+ def insert(*args, &block)
25
+ arr = [:insert, *args]
26
+ arr << block if block
27
+
28
+ namespace_stackable(:middleware, arr)
29
+ end
30
+
31
+ def insert_before(*args, &block)
32
+ arr = [:insert_before, *args]
33
+ arr << block if block
34
+
35
+ namespace_stackable(:middleware, arr)
36
+ end
37
+
38
+ def insert_after(*args, &block)
39
+ arr = [:insert_after, *args]
40
+ arr << block if block
41
+
42
+ namespace_stackable(:middleware, arr)
43
+ end
44
+
45
+ # Retrieve an array of the middleware classes
46
+ # and arguments that are currently applied to the
47
+ # application.
48
+ def middleware
49
+ namespace_stackable(:middleware) || []
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,266 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module DSL
5
+ # Defines DSL methods, meant to be applied to a ParamsScope, which define
6
+ # and describe the parameters accepted by an endpoint, or all endpoints
7
+ # within a namespace.
8
+ module Parameters
9
+ extend ActiveSupport::Concern
10
+
11
+ # Set the module used to build the request.params.
12
+ #
13
+ # @param build_with the ParamBuilder module to use when building request.params
14
+ # Available builders are:
15
+ #
16
+ # * Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder (default)
17
+ # * Grape::Extensions::Hash::ParamBuilder
18
+ # * Grape::Extensions::Hashie::Mash::ParamBuilder
19
+ #
20
+ # @example
21
+ #
22
+ # require 'grape/extenstions/hashie_mash'
23
+ # class API < Grape::API
24
+ # desc "Get collection"
25
+ # params do
26
+ # build_with :hashie_mash
27
+ # requires :user_id, type: Integer
28
+ # end
29
+ # get do
30
+ # params['user_id']
31
+ # end
32
+ # end
33
+ def build_with(build_with)
34
+ @api.namespace_inheritable(:build_params_with, build_with)
35
+ end
36
+
37
+ # Include reusable params rules among current.
38
+ # You can define reusable params with helpers method.
39
+ #
40
+ # @example
41
+ #
42
+ # class API < Grape::API
43
+ # helpers do
44
+ # params :pagination do
45
+ # optional :page, type: Integer
46
+ # optional :per_page, type: Integer
47
+ # end
48
+ # end
49
+ #
50
+ # desc "Get collection"
51
+ # params do
52
+ # use :pagination
53
+ # end
54
+ # get do
55
+ # Collection.page(params[:page]).per(params[:per_page])
56
+ # end
57
+ # end
58
+ def use(*names)
59
+ named_params = @api.namespace_stackable_with_hash(:named_params) || {}
60
+ options = names.extract_options!
61
+ names.each do |name|
62
+ params_block = named_params.fetch(name) do
63
+ raise "Params :#{name} not found!"
64
+ end
65
+
66
+ if options.empty?
67
+ instance_exec(options, &params_block)
68
+ else
69
+ instance_exec(**options, &params_block)
70
+ end
71
+ end
72
+ end
73
+ alias use_scope use
74
+ alias includes use
75
+
76
+ # Require one or more parameters for the current endpoint.
77
+ #
78
+ # @param attrs list of parameters names, or, if :using is
79
+ # passed as an option, which keys to include (:all or :none) from
80
+ # the :using hash. The last key can be a hash, which specifies
81
+ # options for the parameters
82
+ # @option attrs :type [Class] the type to coerce this parameter to before
83
+ # passing it to the endpoint. See {Grape::Validations::Types} for a list of
84
+ # types that are supported automatically. Custom classes may be used
85
+ # where they define a class-level `::parse` method, or in conjunction
86
+ # with the `:coerce_with` parameter. `JSON` may be supplied to denote
87
+ # `JSON`-formatted objects or arrays of objects. `Array[JSON]` accepts
88
+ # the same values as `JSON` but will wrap single objects in an `Array`.
89
+ # @option attrs :types [Array<Class>] may be supplied in place of +:type+
90
+ # to declare an attribute that has multiple allowed types. See
91
+ # {Validations::Types::MultipleTypeCoercer} for more details on coercion
92
+ # and validation rules for variant-type parameters.
93
+ # @option attrs :desc [String] description to document this parameter
94
+ # @option attrs :default [Object] default value, if parameter is optional
95
+ # @option attrs :values [Array] permissable values for this field. If any
96
+ # other value is given, it will be handled as a validation error
97
+ # @option attrs :using [Hash[Symbol => Hash]] a hash defining keys and
98
+ # options, like that returned by {Grape::Entity#documentation}. The value
99
+ # of each key is an options hash accepting the same parameters
100
+ # @option attrs :except [Array[Symbol]] a list of keys to exclude from
101
+ # the :using Hash. The meaning of this depends on if :all or :none was
102
+ # passed; :all + :except will make the :except fields optional, whereas
103
+ # :none + :except will make the :except fields required
104
+ # @option attrs :coerce_with [#parse, #call] method to be used when coercing
105
+ # the parameter to the type named by `attrs[:type]`. Any class or object
106
+ # that defines `::parse` or `::call` may be used.
107
+ #
108
+ # @example
109
+ #
110
+ # params do
111
+ # # Basic usage: require a parameter of a certain type
112
+ # requires :user_id, type: Integer
113
+ #
114
+ # # You don't need to specify type; String is default
115
+ # requires :foo
116
+ #
117
+ # # Multiple params can be specified at once if they share
118
+ # # the same options.
119
+ # requires :x, :y, :z, type: Date
120
+ #
121
+ # # Nested parameters can be handled as hashes. You must
122
+ # # pass in a block, within which you can use any of the
123
+ # # parameters DSL methods.
124
+ # requires :user, type: Hash do
125
+ # requires :name, type: String
126
+ # end
127
+ # end
128
+ def requires(*attrs, &block)
129
+ orig_attrs = attrs.clone
130
+
131
+ opts = attrs.extract_options!.clone
132
+ opts[:presence] = { value: true, message: opts[:message] }
133
+ opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
134
+
135
+ if opts[:using]
136
+ require_required_and_optional_fields(attrs.first, opts)
137
+ else
138
+ validate_attributes(attrs, opts, &block)
139
+ block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, opts.slice(:as))
140
+ end
141
+ end
142
+
143
+ # Allow, but don't require, one or more parameters for the current
144
+ # endpoint.
145
+ # @param (see #requires)
146
+ # @option (see #requires)
147
+ def optional(*attrs, &block)
148
+ orig_attrs = attrs.clone
149
+
150
+ opts = attrs.extract_options!.clone
151
+ type = opts[:type]
152
+ opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
153
+
154
+ # check type for optional parameter group
155
+ if attrs && block
156
+ raise Grape::Exceptions::MissingGroupType if type.nil?
157
+ raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
158
+ end
159
+
160
+ if opts[:using]
161
+ require_optional_fields(attrs.first, opts)
162
+ else
163
+ validate_attributes(attrs, opts, &block)
164
+
165
+ block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, opts.slice(:as))
166
+ end
167
+ end
168
+
169
+ # Define common settings for one or more parameters
170
+ # @param (see #requires)
171
+ # @option (see #requires)
172
+ def with(*attrs, &block)
173
+ new_group_attrs = [@group, attrs.clone.first].compact.reduce(&:deep_merge)
174
+ new_group_scope([new_group_attrs], &block)
175
+ end
176
+
177
+ # Disallow the given parameters to be present in the same request.
178
+ # @param attrs [*Symbol] parameters to validate
179
+ def mutually_exclusive(*attrs)
180
+ validates(attrs, mutual_exclusion: { value: true, message: extract_message_option(attrs) })
181
+ end
182
+
183
+ # Require exactly one of the given parameters to be present.
184
+ # @param (see #mutually_exclusive)
185
+ def exactly_one_of(*attrs)
186
+ validates(attrs, exactly_one_of: { value: true, message: extract_message_option(attrs) })
187
+ end
188
+
189
+ # Require at least one of the given parameters to be present.
190
+ # @param (see #mutually_exclusive)
191
+ def at_least_one_of(*attrs)
192
+ validates(attrs, at_least_one_of: { value: true, message: extract_message_option(attrs) })
193
+ end
194
+
195
+ # Require that either all given params are present, or none are.
196
+ # @param (see #mutually_exclusive)
197
+ def all_or_none_of(*attrs)
198
+ validates(attrs, all_or_none_of: { value: true, message: extract_message_option(attrs) })
199
+ end
200
+
201
+ # Define a block of validations which should be applied if and only if
202
+ # the given parameter is present. The parameters are not nested.
203
+ # @param attr [Symbol] the parameter which, if present, triggers the
204
+ # validations
205
+ # @raise Grape::Exceptions::UnknownParameter if `attr` has not been
206
+ # defined in this scope yet
207
+ # @yield a parameter definition DSL
208
+ def given(*attrs, &block)
209
+ attrs.each do |attr|
210
+ proxy_attr = first_hash_key_or_param(attr)
211
+ raise Grape::Exceptions::UnknownParameter.new(proxy_attr) unless declared_param?(proxy_attr)
212
+ end
213
+ new_lateral_scope(dependent_on: attrs, &block)
214
+ end
215
+
216
+ # Test for whether a certain parameter has been defined in this params
217
+ # block yet.
218
+ # @return [Boolean] whether the parameter has been defined
219
+ def declared_param?(param)
220
+ if lateral?
221
+ # Elements of @declared_params of lateral scope are pushed in @parent. So check them in @parent.
222
+ @parent.declared_param?(param)
223
+ else
224
+ # @declared_params also includes hashes of options and such, but those
225
+ # won't be flattened out.
226
+ @declared_params.flatten.any? do |declared_param_attr|
227
+ first_hash_key_or_param(declared_param_attr.key) == param
228
+ end
229
+ end
230
+ end
231
+
232
+ alias group requires
233
+
234
+ class EmptyOptionalValue; end # rubocop:disable Lint/EmptyClass
235
+
236
+ def map_params(params, element, is_array = false)
237
+ if params.is_a?(Array)
238
+ params.map do |el|
239
+ map_params(el, element, true)
240
+ end
241
+ elsif params.is_a?(Hash)
242
+ params[element] || (@optional && is_array ? EmptyOptionalValue : {})
243
+ elsif params == EmptyOptionalValue
244
+ EmptyOptionalValue
245
+ else
246
+ {}
247
+ end
248
+ end
249
+
250
+ # @param params [Hash] initial hash of parameters
251
+ # @return hash of parameters relevant for the current scope
252
+ # @api private
253
+ def params(params)
254
+ params = @parent.params_meeting_dependency.presence || @parent.params(params) if instance_variable_defined?(:@parent) && @parent
255
+ params = map_params(params, @element) if instance_variable_defined?(:@element) && @element
256
+ params
257
+ end
258
+
259
+ private
260
+
261
+ def first_hash_key_or_param(parameter)
262
+ parameter.is_a?(Hash) ? parameter.keys.first : parameter
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module DSL
5
+ module RequestResponse
6
+ extend ActiveSupport::Concern
7
+
8
+ include Grape::DSL::Configuration
9
+
10
+ module ClassMethods
11
+ # Specify the default format for the API's serializers.
12
+ # May be `:json` or `:txt` (default).
13
+ def default_format(new_format = nil)
14
+ namespace_inheritable(:default_format, new_format.nil? ? nil : new_format.to_sym)
15
+ end
16
+
17
+ # Specify the format for the API's serializers.
18
+ # May be `:json`, `:xml`, `:txt`, etc.
19
+ def format(new_format = nil)
20
+ return namespace_inheritable(:format) unless new_format
21
+
22
+ symbolic_new_format = new_format.to_sym
23
+ namespace_inheritable(:format, symbolic_new_format)
24
+ namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
25
+
26
+ content_type = content_types[symbolic_new_format]
27
+ raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
28
+
29
+ namespace_stackable(:content_types, symbolic_new_format => content_type)
30
+ end
31
+
32
+ # Specify a custom formatter for a content-type.
33
+ def formatter(content_type, new_formatter)
34
+ namespace_stackable(:formatters, content_type.to_sym => new_formatter)
35
+ end
36
+
37
+ # Specify a custom parser for a content-type.
38
+ def parser(content_type, new_parser)
39
+ namespace_stackable(:parsers, content_type.to_sym => new_parser)
40
+ end
41
+
42
+ # Specify a default error formatter.
43
+ def default_error_formatter(new_formatter_name = nil)
44
+ return namespace_inheritable(:default_error_formatter) unless new_formatter_name
45
+
46
+ new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
47
+ namespace_inheritable(:default_error_formatter, new_formatter)
48
+ end
49
+
50
+ def error_formatter(format, options)
51
+ formatter = if options.is_a?(Hash) && options.key?(:with)
52
+ options[:with]
53
+ else
54
+ options
55
+ end
56
+
57
+ namespace_stackable(:error_formatters, format.to_sym => formatter)
58
+ end
59
+
60
+ # Specify additional content-types, e.g.:
61
+ # content_type :xls, 'application/vnd.ms-excel'
62
+ def content_type(key, val)
63
+ namespace_stackable(:content_types, key.to_sym => val)
64
+ end
65
+
66
+ # All available content types.
67
+ def content_types
68
+ c_types = namespace_stackable_with_hash(:content_types)
69
+ Grape::ContentTypes.content_types_for c_types
70
+ end
71
+
72
+ # Specify the default status code for errors.
73
+ def default_error_status(new_status = nil)
74
+ namespace_inheritable(:default_error_status, new_status)
75
+ end
76
+
77
+ # Allows you to rescue certain exceptions that occur to return
78
+ # a grape error rather than raising all the way to the
79
+ # server level.
80
+ #
81
+ # @example Rescue from custom exceptions
82
+ # class ExampleAPI < Grape::API
83
+ # class CustomError < StandardError; end
84
+ #
85
+ # rescue_from CustomError
86
+ # end
87
+ #
88
+ # @overload rescue_from(*exception_classes, **options)
89
+ # @param [Array] exception_classes A list of classes that you want to rescue, or
90
+ # the symbol :all to rescue from all exceptions.
91
+ # @param [Block] block Execution block to handle the given exception.
92
+ # @param [Hash] options Options for the rescue usage.
93
+ # @option options [Boolean] :backtrace Include a backtrace in the rescue response.
94
+ # @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
95
+ # @param [Proc] handler Execution proc to handle the given exception as an
96
+ # alternative to passing a block.
97
+ def rescue_from(*args, &block)
98
+ if args.last.is_a?(Proc)
99
+ handler = args.pop
100
+ elsif block
101
+ handler = block
102
+ end
103
+
104
+ options = args.extract_options!
105
+ raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
106
+
107
+ handler ||= extract_with(options)
108
+
109
+ if args.include?(:all)
110
+ namespace_inheritable(:rescue_all, true)
111
+ namespace_inheritable(:all_rescue_handler, handler)
112
+ elsif args.include?(:grape_exceptions)
113
+ namespace_inheritable(:rescue_all, true)
114
+ namespace_inheritable(:rescue_grape_exceptions, true)
115
+ namespace_inheritable(:grape_exceptions_rescue_handler, handler)
116
+ else
117
+ handler_type =
118
+ case options[:rescue_subclasses]
119
+ when nil, true
120
+ :rescue_handlers
121
+ else
122
+ :base_only_rescue_handlers
123
+ end
124
+
125
+ namespace_reverse_stackable(handler_type, args.to_h { |arg| [arg, handler] })
126
+ end
127
+
128
+ namespace_stackable(:rescue_options, options)
129
+ end
130
+
131
+ # Allows you to specify a default representation entity for a
132
+ # class. This allows you to map your models to their respective
133
+ # entities once and then simply call `present` with the model.
134
+ #
135
+ # @example
136
+ # class ExampleAPI < Grape::API
137
+ # represent User, with: Entity::User
138
+ #
139
+ # get '/me' do
140
+ # present current_user # with: Entity::User is assumed
141
+ # end
142
+ # end
143
+ #
144
+ # Note that Grape will automatically go up the class ancestry to
145
+ # try to find a representing entity, so if you, for example, define
146
+ # an entity to represent `Object` then all presented objects will
147
+ # bubble up and utilize the entity provided on that `represent` call.
148
+ #
149
+ # @param model_class [Class] The model class that will be represented.
150
+ # @option options [Class] :with The entity class that will represent the model.
151
+ def represent(model_class, options)
152
+ raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
153
+
154
+ namespace_stackable(:representations, model_class => options[:with])
155
+ end
156
+
157
+ private
158
+
159
+ def extract_with(options)
160
+ return unless options.key?(:with)
161
+
162
+ with_option = options.delete(:with)
163
+ return with_option if with_option.instance_of?(Proc)
164
+ return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
165
+
166
+ raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end