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
data/UPGRADING.md ADDED
@@ -0,0 +1,1697 @@
1
+ Upgrading Grape
2
+ ===============
3
+
4
+ ### Upgrading to >= 2.4.0
5
+
6
+ #### Grape::Middleware::Auth::Base
7
+ `type` is now validated at compile time and will raise a `Grape::Exceptions::UnknownAuthStrategy` if unknown.
8
+
9
+ #### Grape::Middleware::Base
10
+
11
+ - Second argument `options` is now a double splat (**) instead of single splat (*). If you're redefining `initialize` in your middleware and/or calling `super` in it, you might have to adapt the signature and the `super` call. Also, you might have to remove `{}` if you're pass `options` as a literal `Hash` or add `**` if you're using a variable.
12
+ - `Grape::Middleware::Helpers` has been removed. The equivalent method `context` is now part of `Grape::Middleware::Base`.
13
+
14
+ #### Grape::Http::Headers, Grape::Util::Lazy::Object
15
+
16
+ Both have been removed. See [2554](https://github.com/ruby-grape/grape/pull/2554).
17
+ Here are the notable changes:
18
+
19
+ - Constants like `HTTP_ACCEPT` have been replaced by their literal value.
20
+ - `SUPPORTED_METHODS` has been moved to `Grape` module.
21
+ - `HTTP_HEADERS` has been moved to `Grape::Request` and renamed `KNOWN_HEADERS`. The last has been refreshed with new headers, and it's not lazy anymore.
22
+ - `SUPPORTED_METHODS_WITHOUT_OPTIONS` and `find_supported_method` have been removed.
23
+
24
+ #### Grape::Middleware::Base
25
+
26
+ - Constant `TEXT_HTML` has been removed in favor of using literal string 'text/html'.
27
+ - `rack_request` and `query_params` have been added. Feel free to call these in your middlewares.
28
+
29
+ #### Params Builder
30
+
31
+ - Passing a class to `build_with` or `Grape.config.param_builder` has been deprecated in favor of a symbolized short_name. See `SHORTNAME_LOOKUP` in [params_builder](lib/grape/params_builder.rb).
32
+ - Including Grape's extensions like `Grape::Extensions::Hashie::Mash::ParamBuilder` has been deprecated in favor of using `build_with` at the route level.
33
+
34
+ #### Accept Header Negotiation Harmonized
35
+
36
+ [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept) header is now fully interpreted through `Rack::Utils.best_q_match` which is following [RFC2616 14.1](https://datatracker.ietf.org/doc/html/rfc2616#section-14.1). Since [Grape 2.1.0](https://github.com/ruby-grape/grape/blob/master/CHANGELOG.md#210-20240615), the [header versioning strategy](https://github.com/ruby-grape/grape?tab=readme-ov-file#header) was adhering to it, but `Grape::Middleware::Formatter` never did.
37
+
38
+ Your API might act differently since it will strictly follow the [RFC2616 14.1](https://datatracker.ietf.org/doc/html/rfc2616#section-14.1) when interpreting the `Accept` header. Here are the differences:
39
+
40
+ ##### Invalid or missing quality ranking
41
+ The following used to yield `application/xml` and now will yield `application/json` as the preferred media type:
42
+ - `application/json;q=invalid,application/xml;q=0.5`
43
+ - `application/json,application/xml;q=1.0`
44
+
45
+ For the invalid case, the value `invalid` was automatically `to_f` and `invalid.to_f` equals `0.0`. Now, since it doesn't match [Rack's regex](https://github.com/rack/rack/blob/3-1-stable/lib/rack/utils.rb#L138), its interpreted as non provided and its quality ranking equals 1.0.
46
+
47
+ For the non provided case, 1.0 was automatically assigned and in a case of multiple best matches, the first was returned based on Ruby's sort_by `quality`. Now, 1.0 is still assigned and the last is returned in case of multiple best matches. See [Rack's implementation](https://github.com/rack/rack/blob/e8f47608668d507e0f231a932fa37c9ca551c0a5/lib/rack/utils.rb#L167) of the RFC.
48
+
49
+ ##### Considering the closest generic when vendor tree
50
+ Excluding the [header versioning strategy](https://github.com/ruby-grape/grape?tab=readme-ov-file#header), whenever a media type with the [vendor tree](https://datatracker.ietf.org/doc/html/rfc6838#section-3.2) leading facet `vnd.` like `application/vnd.api+json` was provided, Grape would also consider its closest generic when negotiating. In that case, `application/json` was added to the negotiation. Now, it will just consider the provided media types without considering any closest generics, and you'll need to [register](https://github.com/ruby-grape/grape?tab=readme-ov-file#api-formats) it.
51
+ You can find the official vendor tree registrations on [IANA](https://www.iana.org/assignments/media-types/media-types.xhtml)
52
+
53
+ #### Custom Validators
54
+
55
+ If you now receive an error of `'Grape::Validations.require_validator': unknown validator: your_custom_validation (Grape::Exceptions::UnknownValidator)` after upgrading to 2.4.0 then you will need to ensure that you require the `your_custom_validation` file before your Grape API code is loaded.
56
+
57
+ See [2533](https://github.com/ruby-grape/grape/issues/2533) for more information.
58
+
59
+ ### Upgrading to >= 2.3.0
60
+
61
+ ### `content_type` vs `api.format` inside API
62
+
63
+ Before 2.3.0, `content_type` had priority over `env['api.format']` when set in an API, which was incorrect. The priority has been flipped and `env['api.format']` will be checked first.
64
+ In addition, the function `api_format` has been added. Instead of setting `env['api.format']` directly, you can call `api_format`.
65
+ See [#2506](https://github.com/ruby-grape/grape/pull/2506) for more information.
66
+
67
+ #### Remove Deprecated Methods and Options
68
+
69
+ - Deprecated `file` method has been removed. Use `send_file` or `stream`.
70
+ See [#2500](https://github.com/ruby-grape/grape/pull/2500) for more information.
71
+
72
+ - The `except` and `proc` options have been removed from the `values` validator. Use `except_values` validator or assign `proc` directly to `values`.
73
+ See [#2501](https://github.com/ruby-grape/grape/pull/2501) for more information.
74
+
75
+ - `Passing an options hash and a block to 'desc'` deprecation has been removed. Move all hash options to block instead.
76
+ See [#2502](https://github.com/ruby-grape/grape/pull/2502) for more information.
77
+
78
+ ### Upgrading to >= 2.2.0
79
+
80
+ ### `Length` validator
81
+
82
+ After Grape 2.2.0, `length` validator will only take effect for parameters with types that support `#length` method, will not throw `ArgumentError` exception.
83
+
84
+ See [#2464](https://github.com/ruby-grape/grape/pull/2464) for more information.
85
+
86
+ ### Upgrading to >= 2.1.0
87
+
88
+ #### Optional Builder
89
+
90
+ The `builder` gem dependency has been made optional as it's only used when generating XML. If your code does, add `builder` to your `Gemfile`.
91
+
92
+ See [#2445](https://github.com/ruby-grape/grape/pull/2445) for more information.
93
+
94
+ #### Deep Merging of Parameter Attributes
95
+
96
+ Grape now uses `deep_merge` to combine parameter attributes within the `with` method. Previously, attributes defined at the parameter level would override those defined at the group level.
97
+ With deep merge, attributes are now combined, allowing for more detailed and nuanced API specifications.
98
+
99
+ For example:
100
+
101
+ ```ruby
102
+ with(documentation: { in: 'body' }) do
103
+ optional :vault, documentation: { default: 33 }
104
+ end
105
+ ```
106
+
107
+ Before it was equivalent to:
108
+
109
+ ```ruby
110
+ optional :vault, documentation: { default: 33 }
111
+ ```
112
+
113
+ After it is an equivalent of:
114
+
115
+ ```ruby
116
+ optional :vault, documentation: { in: 'body', default: 33 }
117
+ ```
118
+
119
+ See [#2432](https://github.com/ruby-grape/grape/pull/2432) for more information.
120
+
121
+ #### Zeitwerk
122
+
123
+ Grape's autoloader has been updated and it's now based on [Zeitwerk](https://github.com/fxn/zeitwerk).
124
+ If you MP (Monkey Patch) some files and you're not following the [file structure](https://github.com/fxn/zeitwerk?tab=readme-ov-file#file-structure), you might end up with a Zeitwerk error.
125
+
126
+ See [#2363](https://github.com/ruby-grape/grape/pull/2363) for more information.
127
+
128
+ #### Changes in rescue_from
129
+
130
+ The `rack_response` method has been deprecated and the `error_response` method has been removed. Use `error!` instead.
131
+
132
+ See [#2414](https://github.com/ruby-grape/grape/pull/2414) for more information.
133
+
134
+ #### Change in parameters precedence
135
+
136
+ When using together with `Grape::Extensions::Hash::ParamBuilder`, `route_param` takes higher precedence over a regular parameter defined with same name, which now matches the default param builder behavior.
137
+
138
+ This was a regression introduced by [#2326](https://github.com/ruby-grape/grape/pull/2326) in Grape v1.8.0.
139
+
140
+ ```ruby
141
+ Grape.configure do |config|
142
+ config.param_builder = Grape::Extensions::Hash::ParamBuilder
143
+ end
144
+
145
+ params do
146
+ requires :foo, type: String
147
+ end
148
+ route_param :foo do
149
+ get do
150
+ { value: params[:foo] }
151
+ end
152
+ end
153
+ ```
154
+
155
+ Request:
156
+
157
+ ```bash
158
+ curl -X POST -H "Content-Type: application/json" localhost:9292/bar -d '{"foo": "baz"}'
159
+ ```
160
+
161
+ Response prior to v1.8.0:
162
+
163
+ ```json
164
+ {
165
+ "value": "bar"
166
+ }
167
+ ```
168
+
169
+ v1.8.0..v2.0.0:
170
+
171
+ ```json
172
+ {
173
+ "value": "baz"
174
+ }
175
+ ```
176
+
177
+ v2.1.0+:
178
+
179
+ ```json
180
+ {
181
+ "value": "bar"
182
+ }
183
+ ```
184
+
185
+ See [#2378](https://github.com/ruby-grape/grape/pull/2378) for details.
186
+
187
+ #### Grape::Router::Route.route_xxx methods have been removed
188
+
189
+ - `route_method` is accessible through `request_method`
190
+ - `route_path` is accessible through `path`
191
+ - Any other `route_xyz` are accessible through `options[xyz]`
192
+
193
+ #### Instance variables scope
194
+
195
+ Due to the changes done in [#2377](https://github.com/ruby-grape/grape/pull/2377), the instance variables defined inside each of the endpoints (or inside a `before` validator) are now accessible inside the `rescue_from`. The behavior of the instance variables was undefined until `2.1.0`.
196
+
197
+ If you were using the same variable name defined inside an endpoint or `before` validator inside a `rescue_from` handler, you need to take in mind that you can start getting different values or you can be overriding values.
198
+
199
+ Before:
200
+ ```ruby
201
+ class TwitterAPI < Grape::API
202
+ before do
203
+ @var = 1
204
+ end
205
+
206
+ get '/' do
207
+ puts @var # => 1
208
+ raise
209
+ end
210
+
211
+ rescue_from :all do
212
+ puts @var # => nil
213
+ end
214
+ end
215
+ ```
216
+
217
+ After:
218
+ ```ruby
219
+ class TwitterAPI < Grape::API
220
+ before do
221
+ @var = 1
222
+ end
223
+
224
+ get '/' do
225
+ puts @var # => 1
226
+ raise
227
+ end
228
+
229
+ rescue_from :all do
230
+ puts @var # => 1
231
+ end
232
+ end
233
+ ```
234
+
235
+ #### Recognizing Path
236
+
237
+ Grape now considers the types of the configured `route_params` in order to determine the endpoint that matches with the performed request.
238
+
239
+ So taking into account this `Grape::API` class
240
+
241
+ ```ruby
242
+ class Books < Grape::API
243
+ resource :books do
244
+ route_param :id, type: Integer do
245
+ # GET /books/:id
246
+ get do
247
+ #...
248
+ end
249
+ end
250
+
251
+ resource :share do
252
+ # POST /books/share
253
+ post do
254
+ # ....
255
+ end
256
+ end
257
+ end
258
+ end
259
+ ```
260
+
261
+ Before:
262
+ ```ruby
263
+ API.recognize_path '/books/1' # => /books/:id
264
+ API.recognize_path '/books/share' # => /books/:id
265
+ API.recognize_path '/books/other' # => /books/:id
266
+ ```
267
+
268
+ After:
269
+ ```ruby
270
+ API.recognize_path '/books/1' # => /books/:id
271
+ API.recognize_path '/books/share' # => /books/share
272
+ API.recognize_path '/books/other' # => nil
273
+ ```
274
+
275
+ This implies that before this changes, when you performed `/books/other` and it matched with the `/books/:id` endpoint, you get a `400 Bad Request` response because the type of the provided `:id` param was not an `Integer`. However, after upgrading to version `2.1.0` you will get a `404 Not Found` response, because there is not a defined endpoint that matches with `/books/other`.
276
+
277
+ See [#2379](https://github.com/ruby-grape/grape/pull/2379) for more information.
278
+
279
+ ### Upgrading to >= 2.0.0
280
+
281
+ #### Headers
282
+
283
+ As per [rack/rack#1592](https://github.com/rack/rack/issues/1592) Rack 3 is following the HTTP/2+ semantics which require header names to be lower case. To avoid compatibility issues, starting with Grape 1.9.0, headers will be cased based on what version of Rack you are using.
284
+
285
+ Given this request:
286
+
287
+ ```shell
288
+ curl -H "Content-Type: application/json" -H "Secret-Password: foo" ...
289
+ ```
290
+
291
+ If you are using Rack 3 in your application then the headers will be set to:
292
+
293
+ ```ruby
294
+ { "content-type" => "application/json", "secret-password" => "foo"}
295
+ ```
296
+
297
+ This means if you are checking for header values in your application, you would need to change your code to use downcased keys.
298
+
299
+ ```ruby
300
+ get do
301
+ # This would use headers['Secret-Password'] in Rack < 3
302
+ error!('Unauthorized', 401) unless headers['secret-password'] == 'swordfish'
303
+ end
304
+ ```
305
+
306
+ See [#2355](https://github.com/ruby-grape/grape/pull/2355) for more information.
307
+
308
+ #### Digest auth deprecation
309
+
310
+ Digest auth has been removed along with the deprecation of `Rack::Auth::Digest` in Rack 3.
311
+
312
+ See [#2294](https://github.com/ruby-grape/grape/issues/2294) for more information.
313
+
314
+ ### Upgrading to >= 1.7.0
315
+
316
+ #### Exceptions renaming
317
+
318
+ The following exceptions has been renamed for consistency through exceptions naming :
319
+
320
+ * `MissingGroupTypeError` => `MissingGroupType`
321
+ * `UnsupportedGroupTypeError` => `UnsupportedGroupType`
322
+
323
+ See [#2227](https://github.com/ruby-grape/grape/pull/2227) for more information.
324
+
325
+ #### Handling Multipart Limit Errors
326
+
327
+ Rack supports a configurable limit on the number of files created from multipart parameters (`Rack::Utils.multipart_part_limit`) and raises an error if params are received that create too many files. If you were handling the Rack error directly, Grape now wraps that error in `Grape::Execeptions::TooManyMultipartFiles`. Additionally, Grape will return a 413 status code if the exception goes unhandled.
328
+
329
+ ### Upgrading to >= 1.6.0
330
+
331
+ #### Parameter renaming with :as
332
+
333
+ Prior to 1.6.0 the [parameter renaming](https://github.com/ruby-grape/grape#renaming) with `:as` was directly touching the request payload ([`#params`](https://github.com/ruby-grape/grape#parameters)) while duplicating the old and the new key to be both available in the hash. This allowed clients to bypass any validation in case they knew the internal name of the parameter. Unfortunately, in combination with [grape-swagger](https://github.com/ruby-grape/grape-swagger) the internal name (name set with `:as`) of the parameters were documented.
334
+
335
+ This behavior was fixed. Parameter renaming is now done when using the [`#declared(params)`](https://github.com/ruby-grape/grape#declared) parameters helper. This stops confusing validation/coercion behavior.
336
+
337
+ Here comes an illustration of the old and new behaviour as code:
338
+
339
+ ```ruby
340
+ # (1) Rename a to b, while client sends +a+
341
+ optional :a, type: Integer, as: :b
342
+ params = { a: 1 }
343
+ declared(params, include_missing: false)
344
+ # expected => { b: 1 }
345
+ # actual => { b: 1 }
346
+
347
+ # (2) Rename a to b, while client sends +b+
348
+ optional :a, type: Integer, as: :b, values: [1, 2, 3]
349
+ params = { b: '5' }
350
+ declared(params, include_missing: false)
351
+ # expected => { } (>= 1.6.0)
352
+ # actual => { b: '5' } (uncasted, unvalidated, <= 1.5.3)
353
+ ```
354
+
355
+ Another implication of this change is the dependent parameter resolution. Prior to 1.6.0 the following code produced a `Grape::Exceptions::UnknownParameter` because `:a` was replaced by `:b`:
356
+
357
+ ```ruby
358
+ params do
359
+ optional :a, as: :b
360
+ given :a do # (<= 1.5.3 you had to reference +:b+ here to make it work)
361
+ requires :c
362
+ end
363
+ end
364
+ ```
365
+
366
+ This code now works without any errors, as the renaming is just an internal behaviour of the `#declared(params)` parameter helper.
367
+
368
+ See [#2189](https://github.com/ruby-grape/grape/pull/2189) for more information.
369
+
370
+ ### Upgrading to >= 1.5.3
371
+
372
+ #### Nil value and coercion
373
+
374
+ Prior to 1.2.5 version passing a `nil` value for a parameter with a custom coercer would invoke the coercer, and not passing a parameter would not invoke it.
375
+ This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
376
+
377
+ ```ruby
378
+ class Api < Grape::API
379
+ params do
380
+ optional :value, type: Integer, coerce_with: ->(val) { val || 0 }
381
+ end
382
+
383
+ get 'example' do
384
+ params[:my_param]
385
+ end
386
+ get '/example', params: { value: nil }
387
+ # 1.5.2 = nil
388
+ # 1.5.3 = 0
389
+ get '/example', params: {}
390
+ # 1.5.2 = nil
391
+ # 1.5.3 = nil
392
+ end
393
+ ```
394
+ See [#2164](https://github.com/ruby-grape/grape/pull/2164) for more information.
395
+
396
+ ### Upgrading to >= 1.5.1
397
+
398
+ #### Dependent params
399
+
400
+ If you use [dependent params](https://github.com/ruby-grape/grape#dependent-parameters) with
401
+ `Grape::Extensions::Hash::ParamBuilder`, make sure a parameter to be dependent on is set as a Symbol.
402
+ If a String is given, a parameter that other parameters depend on won't be found even if it is present.
403
+
404
+ _Correct_:
405
+ ```ruby
406
+ given :matrix do
407
+ # dependent params
408
+ end
409
+ ```
410
+
411
+ _Wrong_:
412
+ ```ruby
413
+ given 'matrix' do
414
+ # dependent params
415
+ end
416
+ ```
417
+
418
+ ### Upgrading to >= 1.5.0
419
+
420
+ Prior to 1.3.3, the `declared` helper would always return the complete params structure if `include_missing=true` was set. In 1.3.3 a regression was introduced such that a missing Hash with or without nested parameters would always resolve to `{}`.
421
+
422
+ In 1.5.0 this behavior is reverted, so the whole params structure will always be available via `declared`, regardless of whether any params are passed.
423
+
424
+ The following rules now apply to the `declared` helper when params are missing and `include_missing=true`:
425
+
426
+ * Hash params with children will resolve to a Hash with keys for each declared child.
427
+ * Hash params with no children will resolve to `{}`.
428
+ * Set params will resolve to `Set.new`.
429
+ * Array params will resolve to `[]`.
430
+ * All other params will resolve to `nil`.
431
+
432
+ #### Example
433
+
434
+ ```ruby
435
+ class Api < Grape::API
436
+ params do
437
+ optional :outer, type: Hash do
438
+ optional :inner, type: Hash do
439
+ optional :value, type: String
440
+ end
441
+ end
442
+ end
443
+ get 'example' do
444
+ declared(params, include_missing: true)
445
+ end
446
+ end
447
+ ```
448
+
449
+ ```
450
+ get '/example'
451
+ # 1.3.3 = {}
452
+ # 1.5.0 = {outer: {inner: {value:null}}}
453
+ ```
454
+
455
+ For more information see [#2103](https://github.com/ruby-grape/grape/pull/2103).
456
+
457
+ ### Upgrading to >= 1.4.0
458
+
459
+ #### Reworking stream and file and un-deprecating stream like-objects
460
+
461
+ Previously in 0.16 stream-like objects were deprecated. This release restores their functionality for use-cases other than file streaming.
462
+
463
+ This release deprecated `file` in favor of `sendfile` to better document its purpose.
464
+
465
+ To deliver a file via the Sendfile support in your web server and have the Rack::Sendfile middleware enabled. See [`Rack::Sendfile`](https://www.rubydoc.info/gems/rack/Rack/Sendfile).
466
+ ```ruby
467
+ class API < Grape::API
468
+ get '/' do
469
+ sendfile '/path/to/file'
470
+ end
471
+ end
472
+ ```
473
+
474
+ Use `stream` to stream file content in chunks.
475
+
476
+ ```ruby
477
+ class API < Grape::API
478
+ get '/' do
479
+ stream '/path/to/file'
480
+ end
481
+ end
482
+ ```
483
+
484
+ Or use `stream` to stream other kinds of content. In the following example a streamer class
485
+ streams paginated data from a database.
486
+
487
+ ```ruby
488
+ class MyObject
489
+ attr_accessor :result
490
+
491
+ def initialize(query)
492
+ @result = query
493
+ end
494
+
495
+ def each
496
+ yield '['
497
+ # Do paginated DB fetches and return each page formatted
498
+ first = false
499
+ result.find_in_batches do |records|
500
+ yield process_records(records, first)
501
+ first = false
502
+ end
503
+ yield ']'
504
+ end
505
+
506
+ def process_records(records, first)
507
+ buffer = +''
508
+ buffer << ',' unless first
509
+ buffer << records.map(&:to_json).join(',')
510
+ buffer
511
+ end
512
+ end
513
+
514
+ class API < Grape::API
515
+ get '/' do
516
+ stream MyObject.new(Sprocket.all)
517
+ end
518
+ end
519
+ ```
520
+
521
+ ### Upgrading to >= 1.3.3
522
+
523
+ #### Nil values for structures
524
+
525
+ Nil values have always been a special case when dealing with types, especially with the following structures:
526
+
527
+ - Array
528
+ - Hash
529
+ - Set
530
+
531
+ The behavior for these structures has changed throughout the latest releases. For example:
532
+
533
+ ```ruby
534
+ class Api < Grape::API
535
+ params do
536
+ require :my_param, type: Array[Integer]
537
+ end
538
+
539
+ get 'example' do
540
+ params[:my_param]
541
+ end
542
+ get '/example', params: { my_param: nil }
543
+ # 1.3.1 = []
544
+ # 1.3.2 = nil
545
+ end
546
+ ```
547
+
548
+ For now on, `nil` values stay `nil` values for all types, including arrays, sets and hashes.
549
+
550
+ If you want to have the same behavior as 1.3.1, apply a `default` validator:
551
+
552
+ ```ruby
553
+ class Api < Grape::API
554
+ params do
555
+ require :my_param, type: Array[Integer], default: []
556
+ end
557
+
558
+ get 'example' do
559
+ params[:my_param]
560
+ end
561
+ get '/example', params: { my_param: nil } # => []
562
+ end
563
+ ```
564
+
565
+ #### Default validator
566
+
567
+ Default validator is now applied for `nil` values.
568
+
569
+ ```ruby
570
+ class Api < Grape::API
571
+ params do
572
+ requires :my_param, type: Integer, default: 0
573
+ end
574
+
575
+ get 'example' do
576
+ params[:my_param]
577
+ end
578
+ get '/example', params: { my_param: nil } #=> before: nil, after: 0
579
+ end
580
+ ```
581
+
582
+ ### Upgrading to >= 1.3.0
583
+
584
+ You will need to upgrade to this version if you depend on `rack >= 2.1.0`.
585
+
586
+ #### Ruby
587
+
588
+ After adding dry-types, Ruby 2.4 or newer is required.
589
+
590
+ #### Coercion
591
+
592
+ [Virtus](https://github.com/solnic/virtus) has been replaced by [dry-types](https://dry-rb.org/gems/dry-types/1.2/) for parameter coercion. If your project depends on Virtus outside of Grape, explicitly add it to your `Gemfile`.
593
+
594
+ Here's an example of how to migrate a custom type from Virtus to dry-types:
595
+
596
+ ```ruby
597
+ # Legacy Grape parser
598
+ class SecureUriType < Virtus::Attribute
599
+ def coerce(input)
600
+ URI.parse value
601
+ end
602
+
603
+ def value_coerced?(input)
604
+ value.is_a? String
605
+ end
606
+ end
607
+
608
+ params do
609
+ requires :secure_uri, type: SecureUri
610
+ end
611
+ ```
612
+
613
+ To use dry-types, we need to:
614
+
615
+ 1. Remove the inheritance of `Virtus::Attribute`
616
+ 1. Rename `coerce` to `self.parse`
617
+ 1. Rename `value_coerced?` to `self.parsed?`
618
+
619
+ The custom type must have a class-level `parse` method to the model. A class-level `parsed?` is needed if the parsed type differs from the defined type. In the example below, since `SecureUri` is not the same as `URI::HTTPS`, `self.parsed?` is needed:
620
+
621
+ ```ruby
622
+ # New dry-types parser
623
+ class SecureUri
624
+ def self.parse(value)
625
+ URI.parse value
626
+ end
627
+
628
+ def self.parsed?(value)
629
+ value.is_a? URI::HTTPS
630
+ end
631
+ end
632
+
633
+ params do
634
+ requires :secure_uri, type: SecureUri
635
+ end
636
+ ```
637
+
638
+ #### Coercing to `FalseClass` or `TrueClass` no longer works
639
+
640
+ Previous Grape versions allowed this, though it wasn't documented:
641
+
642
+ ```ruby
643
+ requires :true_value, type: TrueClass
644
+ requires :bool_value, types: [FalseClass, TrueClass]
645
+ ```
646
+
647
+ This is no longer supported, if you do this, your values will never be valid. Instead you should do this:
648
+
649
+ ```ruby
650
+ requires :true_value, type: Boolean # in your endpoint you should validate if this is actually `true`
651
+ requires :bool_value, type: Boolean
652
+ ```
653
+
654
+ #### Ensure that Array types have explicit coercions
655
+
656
+ Unlike Virtus, dry-types does not perform any implict coercions. If you have any uses of `Array[String]`, `Array[Integer]`, etc. be sure they use a `coerce_with` block. For example:
657
+
658
+ ```ruby
659
+ requires :values, type: Array[String]
660
+ ```
661
+
662
+ It's quite common to pass a comma-separated list, such as `tag1,tag2` as `values`. Previously Virtus would implicitly coerce this to `Array(values)` so that `["tag1,tag2"]` would pass the type checks, but with `dry-types` the values are no longer coerced for you. To fix this, you might do:
663
+
664
+ ```ruby
665
+ requires :values, type: Array[String], coerce_with: ->(val) { val.split(',').map(&:strip) }
666
+ ```
667
+
668
+ Likewise, for `Array[Integer]`, you might do:
669
+
670
+ ```ruby
671
+ requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(',').map(&:strip).map(&:to_i) }
672
+ ```
673
+
674
+ For more information see [#1920](https://github.com/ruby-grape/grape/pull/1920).
675
+
676
+ ### Upgrading to >= 1.2.4
677
+
678
+ #### Headers in `error!` call
679
+
680
+ Headers in `error!` will be merged with `headers` hash. If any header need to be cleared on `error!` call, make sure to move it to the `after` block.
681
+
682
+ ```ruby
683
+ class SampleApi < Grape::API
684
+ before do
685
+ header 'X-Before-Header', 'before_call'
686
+ end
687
+
688
+ get 'ping' do
689
+ header 'X-App-Header', 'on_call'
690
+ error! :pong, 400, 'X-Error-Details' => 'Invalid token'
691
+ end
692
+ end
693
+ ```
694
+ **Former behaviour**
695
+ ```ruby
696
+ response.headers['X-Before-Header'] # => nil
697
+ response.headers['X-App-Header'] # => nil
698
+ response.headers['X-Error-Details'] # => Invalid token
699
+ ```
700
+
701
+ **Current behaviour**
702
+ ```ruby
703
+ response.headers['X-Before-Header'] # => 'before_call'
704
+ response.headers['X-App-Header'] # => 'on_call'
705
+ response.headers['X-Error-Details'] # => Invalid token
706
+ ```
707
+
708
+ ### Upgrading to >= 1.2.1
709
+
710
+ #### Obtaining the name of a mounted class
711
+
712
+ In order to make obtaining the name of a mounted class simpler, we've delegated `.to_s` to `base.name`
713
+
714
+ **Deprecated in 1.2.0**
715
+ ```ruby
716
+ payload[:endpoint].options[:for].name
717
+ ```
718
+ **New**
719
+ ```ruby
720
+ payload[:endpoint].options[:for].to_s
721
+ ```
722
+
723
+ ### Upgrading to >= 1.2.0
724
+
725
+ #### Changes in the Grape::API class
726
+
727
+ ##### Patching the class
728
+
729
+ In an effort to make APIs re-mountable, The class `Grape::API` no longer refers to an API instance, rather, what used to be `Grape::API` is now `Grape::API::Instance` and `Grape::API` was replaced with a class that can contain several instances of `Grape::API`.
730
+
731
+ This changes were done in such a way that no code-changes should be required. However, if experiencing problems, or relying on private methods and internal behaviour too deeply, it is possible to restore the prior behaviour by replacing the references from `Grape::API` to `Grape::API::Instance`.
732
+
733
+ Note, this is particularly relevant if you are opening the class `Grape::API` for modification.
734
+
735
+ **Deprecated**
736
+ ```ruby
737
+ class Grape::API
738
+ # your patched logic
739
+ ...
740
+ end
741
+ ```
742
+ **New**
743
+ ```ruby
744
+ class Grape::API::Instance
745
+ # your patched logic
746
+ ...
747
+ end
748
+ ```
749
+
750
+ ##### `name` (and other caveats) of the mounted API
751
+
752
+ After the patch, the mounted API is no longer a Named class inheriting from `Grape::API`, it is an anonymous class which inherit from `Grape::API::Instance`.
753
+
754
+ What this means in practice, is:
755
+
756
+ - Generally: you can access the named class from the instance calling the getter `base`.
757
+ - In particular: If you need the `name`, you can use `base`.`name`.
758
+
759
+ **Deprecated**
760
+
761
+ ```ruby
762
+ payload[:endpoint].options[:for].name
763
+ ```
764
+
765
+ **New**
766
+
767
+ ```ruby
768
+ payload[:endpoint].options[:for].base.name
769
+ ```
770
+
771
+ #### Changes in rescue_from returned object
772
+
773
+ Grape will now check the object returned from `rescue_from` and ensure that it is a `Rack::Response`. That makes sure response is valid and avoids exposing service information. Change any code that invoked `Rack::Response.new(...).finish` in a custom `rescue_from` block to `Rack::Response.new(...)` to comply with the validation.
774
+
775
+ ```ruby
776
+ class Twitter::API < Grape::API
777
+ rescue_from :all do |e|
778
+ # version prior to 1.2.0
779
+ Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' }).finish
780
+ # 1.2.0 version
781
+ Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' })
782
+ end
783
+ end
784
+ ```
785
+
786
+ See [#1757](https://github.com/ruby-grape/grape/pull/1757) and [#1776](https://github.com/ruby-grape/grape/pull/1776) for more information.
787
+
788
+ ### Upgrading to >= 1.1.0
789
+
790
+ #### Changes in HTTP Response Code for Unsupported Content Type
791
+
792
+ For PUT, POST, PATCH, and DELETE requests where a non-empty body and a "Content-Type" header is supplied that is not supported by the Grape API, Grape will no longer return a 406 "Not Acceptable" HTTP status code and will instead return a 415 "Unsupported Media Type" so that the usage of HTTP status code falls more in line with the specification of [RFC 2616](https://www.ietf.org/rfc/rfc2616.txt).
793
+
794
+ ### Upgrading to >= 1.0.0
795
+
796
+ #### Changes in XML and JSON Parsers
797
+
798
+ Grape no longer uses `multi_json` or `multi_xml` by default and uses `JSON` and `ActiveSupport::XmlMini` instead. This has no visible impact on JSON processing, but the default behavior of the XML parser has changed. For example, an XML POST containing `<user>Bobby T.</user>` was parsed as `Bobby T.` with `multi_xml`, and as now parsed as `{"__content__"=>"Bobby T."}` with `XmlMini`.
799
+
800
+ If you were using `MultiJson.load`, `MultiJson.dump` or `MultiXml.parse`, you can substitute those with `Grape::Json.load`, `Grape::Json.dump`, `::Grape::Xml.parse`, or directly with `JSON.load`, `JSON.dump`, `XmlMini.parse`, etc.
801
+
802
+ To restore previous behavior, add `multi_json` or `multi_xml` to your `Gemfile` and `require` it.
803
+
804
+ See [#1623](https://github.com/ruby-grape/grape/pull/1623) for more information.
805
+
806
+ #### Changes in Parameter Class
807
+
808
+ The default class for `params` has changed from `Hashie::Mash` to `ActiveSupport::HashWithIndifferentAccess` and the `hashie` dependency has been removed. This means that by default you can no longer access parameters by method name.
809
+
810
+ ```ruby
811
+ class API < Grape::API
812
+ params do
813
+ optional :color, type: String
814
+ end
815
+ get do
816
+ params[:color] # use params[:color] instead of params.color
817
+ end
818
+ end
819
+ ```
820
+
821
+ To restore the behavior of prior versions, add `hashie` to your `Gemfile` and `include Grape::Extensions::Hashie::Mash::ParamBuilder` in your API.
822
+
823
+ ```ruby
824
+ class API < Grape::API
825
+ include Grape::Extensions::Hashie::Mash::ParamBuilder
826
+
827
+ params do
828
+ optional :color, type: String
829
+ end
830
+ get do
831
+ # params.color works
832
+ end
833
+ end
834
+ ```
835
+
836
+ This behavior can also be overridden on individual parameter blocks using `build_with`.
837
+
838
+ ```ruby
839
+ params do
840
+ build_with Grape::Extensions::Hash::ParamBuilder
841
+ optional :color, type: String
842
+ end
843
+ ```
844
+
845
+ If you're constructing your own `Grape::Request` in a middleware, you can pass different parameter handlers to create the desired `params` class with `build_params_with`.
846
+
847
+ ```ruby
848
+ def request
849
+ Grape::Request.new(env, build_params_with: Grape::Extensions::Hashie::Mash::ParamBuilder)
850
+ end
851
+ ```
852
+
853
+ See [#1610](https://github.com/ruby-grape/grape/pull/1610) for more information.
854
+
855
+ #### The `except`, `except_message`, and `proc` options of the `values` validator are deprecated.
856
+
857
+ The new `except_values` validator should be used in place of the `except` and `except_message` options of the `values` validator.
858
+
859
+ Arity one Procs may now be used directly as the `values` option to explicitly test param values.
860
+
861
+ **Deprecated**
862
+ ```ruby
863
+ params do
864
+ requires :a, values: { value: 0..99, except: [3] }
865
+ requires :b, values: { value: 0..99, except: [3], except_message: 'not allowed' }
866
+ requires :c, values: { except: ['admin'] }
867
+ requires :d, values: { proc: -> (v) { v.even? } }
868
+ end
869
+ ```
870
+ **New**
871
+ ```ruby
872
+ params do
873
+ requires :a, values: 0..99, except_values: [3]
874
+ requires :b, values: 0..99, except_values: { value: [3], message: 'not allowed' }
875
+ requires :c, except_values: ['admin']
876
+ requires :d, values: -> (v) { v.even? }
877
+ end
878
+ ```
879
+
880
+ See [#1616](https://github.com/ruby-grape/grape/pull/1616) for more information.
881
+
882
+ ### Upgrading to >= 0.19.1
883
+
884
+ #### DELETE now defaults to status code 200 for responses with a body, or 204 otherwise
885
+
886
+ Prior to this version, DELETE requests defaulted to a status code of 204 No Content, even when the response included content. This behavior confused some clients and prevented the formatter middleware from running properly. As of this version, DELETE requests will only default to a 204 No Content status code if no response body is provided, and will default to 200 OK otherwise.
887
+
888
+ Specifically, DELETE behaviour has changed as follows:
889
+
890
+ - In versions < 0.19.0, all DELETE requests defaulted to a 200 OK status code.
891
+ - In version 0.19.0, all DELETE requests defaulted to a 204 No Content status code, even when content was included in the response.
892
+ - As of version 0.19.1, DELETE requests default to a 204 No Content status code, unless content is supplied, in which case they default to a 200 OK status code.
893
+
894
+ To achieve the old behavior, one can specify the status code explicitly:
895
+
896
+ ```ruby
897
+ delete :id do
898
+ status 204 # or 200, for < 0.19.0 behavior
899
+ 'foo successfully deleted'
900
+ end
901
+ ```
902
+
903
+ One can also use the new `return_no_content` helper to explicitly return a 204 status code and an empty body for any request type:
904
+
905
+ ```ruby
906
+ delete :id do
907
+ return_no_content
908
+ 'this will not be returned'
909
+ end
910
+ ```
911
+
912
+ See [#1550](https://github.com/ruby-grape/grape/pull/1550) for more information.
913
+
914
+ ### Upgrading to >= 0.18.1
915
+
916
+ #### Changes in priority of :any routes
917
+
918
+ Prior to this version, `:any` routes were searched after matching first route and 405 routes. This behavior has changed and `:any` routes are now searched before 405 processing. In the following example the `:any` route will match first when making a request with an unsupported verb.
919
+
920
+ ```ruby
921
+ post :example do
922
+ 'example'
923
+ end
924
+ route :any, '*path' do
925
+ error! :not_found, 404
926
+ end
927
+
928
+ get '/example' #=> before: 405, after: 404
929
+ ```
930
+
931
+ #### Removed param processing from built-in OPTIONS handler
932
+
933
+ When a request is made to the built-in `OPTIONS` handler, only the `before` and `after` callbacks associated with the resource will be run. The `before_validation` and `after_validation` callbacks and parameter validations will be skipped.
934
+
935
+ See [#1505](https://github.com/ruby-grape/grape/pull/1505) for more information.
936
+
937
+ #### Changed endpoint params validation
938
+
939
+ Grape now correctly returns validation errors for all params when multiple params are passed to a requires.
940
+ The following code will return `one is missing, two is missing` when calling the endpoint without parameters.
941
+
942
+ ```ruby
943
+ params do
944
+ requires :one, :two
945
+ end
946
+ ```
947
+
948
+ Prior to this version the response would be `one is missing`.
949
+
950
+ See [#1510](https://github.com/ruby-grape/grape/pull/1510) for more information.
951
+
952
+ #### The default status code for DELETE is now 204 instead of 200.
953
+
954
+ Breaking change: Sets the default response status code for a delete request to 204. A status of 204 makes the response more distinguishable and therefore easier to handle on the client side, particularly because a DELETE request typically returns an empty body as the resource was deleted or voided.
955
+
956
+ To achieve the old behavior, one has to set it explicitly:
957
+ ```ruby
958
+ delete :id do
959
+ status 200
960
+ 'foo successfully deleted'
961
+ end
962
+ ```
963
+
964
+ For more information see: [#1532](https://github.com/ruby-grape/grape/pull/1532).
965
+
966
+ ### Upgrading to >= 0.17.0
967
+
968
+ #### Removed official support for Ruby < 2.2.2
969
+
970
+ Grape is no longer automatically tested against versions of Ruby prior to 2.2.2. This is because of its dependency on activesupport which, with version 5.0.0, now requires at least Ruby 2.2.2.
971
+
972
+ See [#1441](https://github.com/ruby-grape/grape/pull/1441) for nmore information.
973
+
974
+ #### Changed priority of `rescue_from` clauses applying
975
+
976
+ The `rescue_from` clauses declared inside a namespace would take a priority over ones declared in the root scope.
977
+ This could possibly affect those users who use different `rescue_from` clauses in root scope and in namespaces.
978
+
979
+ See [#1405](https://github.com/ruby-grape/grape/pull/1405) for more information.
980
+
981
+ #### Helper methods injected inside `rescue_from` in middleware
982
+
983
+ Helper methods are injected inside `rescue_from` may cause undesirable effects. For example, definining a helper method called `error!` will take precendence over the built-in `error!` method and should be renamed.
984
+
985
+ See [#1451](https://github.com/ruby-grape/grape/issues/1451) for an example.
986
+
987
+ ### Upgrading to >= 0.16.0
988
+
989
+ #### Replace rack-mount with new router
990
+
991
+ The `Route#route_xyz` methods have been deprecated since 0.15.1.
992
+
993
+ Please use `Route#xyz` instead.
994
+
995
+ Note that the `Route#route_method` was replaced by `Route#request_method`.
996
+
997
+ The following code would work correctly.
998
+
999
+ ```ruby
1000
+ TwitterAPI::versions # yields [ 'v1', 'v2' ]
1001
+ TwitterAPI::routes # yields an array of Grape::Route objects
1002
+ TwitterAPI::routes[0].version # => 'v1'
1003
+ TwitterAPI::routes[0].description # => 'Includes custom settings.'
1004
+ TwitterAPI::routes[0].settings[:custom] # => { key: 'value' }
1005
+
1006
+ TwitterAPI::routes[0].request_method # => 'GET'
1007
+ ```
1008
+
1009
+ #### `file` method accepts path to file
1010
+
1011
+ Now to serve files via Grape just pass the path to the file. Functionality with FileStreamer-like objects is deprecated.
1012
+
1013
+ Please, replace your FileStreamer-like objects with paths of served files.
1014
+
1015
+ Old style:
1016
+
1017
+ ```ruby
1018
+ class FileStreamer
1019
+ def initialize(file_path)
1020
+ @file_path = file_path
1021
+ end
1022
+
1023
+ def each(&blk)
1024
+ File.open(@file_path, 'rb') do |file|
1025
+ file.each(10, &blk)
1026
+ end
1027
+ end
1028
+ end
1029
+
1030
+ # ...
1031
+
1032
+ class API < Grape::API
1033
+ get '/' do
1034
+ file FileStreamer.new('/path/to/file')
1035
+ end
1036
+ end
1037
+ ```
1038
+
1039
+ New style:
1040
+
1041
+ ```ruby
1042
+ class API < Grape::API
1043
+ get '/' do
1044
+ file '/path/to/file'
1045
+ end
1046
+ end
1047
+ ```
1048
+
1049
+ ### Upgrading to >= 0.15.0
1050
+
1051
+ #### Changes to availability of `:with` option of `rescue_from` method
1052
+
1053
+ The `:with` option of `rescue_from` does not accept value except Proc, String or Symbol now.
1054
+
1055
+ If you have been depending the old behavior, you should use lambda block instead.
1056
+
1057
+ ```ruby
1058
+ class API < Grape::API
1059
+ rescue_from :all, with: -> { Rack::Response.new('rescued with a method', 400) }
1060
+ end
1061
+ ```
1062
+
1063
+ #### Changes to behavior of `after` method of middleware on error
1064
+
1065
+ The `after` method of the middleware is now also called on error. The following code would work correctly.
1066
+
1067
+ ```ruby
1068
+ class ErrorMiddleware < Grape::Middleware::Base
1069
+ def after
1070
+ return unless @app_response && @app_response[0] == 500
1071
+ env['rack.logger'].debug("Raised error on #{env['PATH_INFO']}")
1072
+ end
1073
+ end
1074
+ ```
1075
+
1076
+ See [#1147](https://github.com/ruby-grape/grape/issues/1147) and [#1240](https://github.com/ruby-grape/grape/issues/1240) for discussion of the issues.
1077
+
1078
+ A warning will be logged if an exception is raised in an `after` callback, which points you to middleware that was not called in the previous version and is called now.
1079
+
1080
+ ```
1081
+ caught error of type NoMethodError in after callback inside Api::Middleware::SomeMiddleware : undefined method `headers' for nil:NilClass
1082
+ ```
1083
+
1084
+ See [#1285](https://github.com/ruby-grape/grape/pull/1285) for more information.
1085
+
1086
+ #### Changes to Method Not Allowed routes
1087
+
1088
+ A `405 Method Not Allowed` error now causes `Grape::Exceptions::MethodNotAllowed` to be raised, which will be rescued via `rescue_from :all`. Restore old behavior with the following error handler.
1089
+
1090
+ ```ruby
1091
+ rescue_from Grape::Exceptions::MethodNotAllowed do |e|
1092
+ error! e.message, e.status, e.headers
1093
+ end
1094
+ ```
1095
+
1096
+ See [#1283](https://github.com/ruby-grape/grape/pull/1283) for more information.
1097
+
1098
+ #### Changes to Grape::Exceptions::Validation parameters
1099
+
1100
+ When raising `Grape::Exceptions::Validation` explicitly, replace `message_key` with `message`.
1101
+
1102
+ For example,
1103
+
1104
+ ```ruby
1105
+ fail Grape::Exceptions::Validation, params: [:oauth_token_secret], message_key: :presence
1106
+ ```
1107
+
1108
+ becomes
1109
+
1110
+ ```ruby
1111
+ fail Grape::Exceptions::Validation, params: [:oauth_token_secret], message: :presence
1112
+ ```
1113
+
1114
+ See [#1295](https://github.com/ruby-grape/grape/pull/1295) for more information.
1115
+
1116
+ ### Upgrading to >= 0.14.0
1117
+
1118
+ #### Changes to availability of DSL methods in filters
1119
+
1120
+ The `#declared` method of the route DSL is no longer available in the `before` filter. Using `declared` in a `before` filter will now raise `Grape::DSL::InsideRoute::MethodNotYetAvailable`.
1121
+
1122
+ See [#1074](https://github.com/ruby-grape/grape/issues/1074) for discussion of the issue.
1123
+
1124
+ #### Changes to header versioning and invalid header version handling
1125
+
1126
+ Identical endpoints with different versions now work correctly. A regression introduced in Grape 0.11.0 caused all but the first-mounted version for such an endpoint to wrongly throw an `InvalidAcceptHeader`. As a side effect, requests with a correct vendor but invalid version can no longer be rescued from a `rescue_from` block.
1127
+
1128
+ See [#1114](https://github.com/ruby-grape/grape/pull/1114) for more information.
1129
+
1130
+ #### Bypasses formatters when status code indicates no content
1131
+
1132
+ To be consistent with rack and it's handling of standard responses associated with no content, both default and custom formatters will now be bypassed when processing responses for status codes defined [by rack](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
1133
+
1134
+ See [#1190](https://github.com/ruby-grape/grape/pull/1190) for more information.
1135
+
1136
+ #### Redirects respond as plain text with message
1137
+
1138
+ `#redirect` now uses `text/plain` regardless of whether that format has been enabled. This prevents formatters from attempting to serialize the message body and allows for a descriptive message body to be provided - and optionally overridden - that better fulfills the theme of the HTTP spec.
1139
+
1140
+ See [#1194](https://github.com/ruby-grape/grape/pull/1194) for more information.
1141
+
1142
+ ### Upgrading to >= 0.12.0
1143
+
1144
+ #### Changes in middleware
1145
+
1146
+ The Rack response object is no longer converted to an array by the formatter, enabling streaming. If your custom middleware is accessing `@app_response`, update it to expect a `Rack::Response` instance instead of an array.
1147
+
1148
+ For example,
1149
+
1150
+ ```ruby
1151
+ class CacheBusterMiddleware < Grape::Middleware::Base
1152
+ def after
1153
+ @app_response[1]['Expires'] = Time.at(0).utc.to_s
1154
+ @app_response
1155
+ end
1156
+ end
1157
+ ```
1158
+
1159
+ becomes
1160
+
1161
+ ```ruby
1162
+ class CacheBusterMiddleware < Grape::Middleware::Base
1163
+ def after
1164
+ @app_response.headers['Expires'] = Time.at(0).utc.to_s
1165
+ @app_response
1166
+ end
1167
+ end
1168
+ ```
1169
+
1170
+ See [#1029](https://github.com/ruby-grape/grape/pull/1029) for more information.
1171
+
1172
+ There is a known issue because of this change. When Grape is used with an older than 1.2.4 version of [warden](https://github.com/hassox/warden) there may be raised the following exception having the [rack-mount](https://github.com/jm/rack-mount) gem's lines as last ones in the backtrace:
1173
+
1174
+ ```
1175
+ NoMethodError: undefined method `[]' for nil:NilClass
1176
+ ```
1177
+
1178
+ The issue can be solved by upgrading warden to 1.2.4 version.
1179
+
1180
+ See [#1151](https://github.com/ruby-grape/grape/issues/1151) for more information.
1181
+
1182
+ #### Changes in present
1183
+
1184
+ Using `present` with objects that responded to `merge` would cause early evaluation of the represented object, with unexpected side-effects, such as missing parameters or environment within rendering code. Grape now only merges represented objects with a previously rendered body, usually when multiple `present` calls are made in the same route.
1185
+
1186
+ See [grape-with-roar#5](https://github.com/dblock/grape-with-roar/issues/5) and [#1023](https://github.com/ruby-grape/grape/issues/1023).
1187
+
1188
+ #### Changes to regexp validator
1189
+
1190
+ Parameters with `nil` value will now pass `regexp` validation. To disallow `nil` value for an endpoint, add `allow_blank: false`.
1191
+
1192
+ ```ruby
1193
+ params do
1194
+ requires :email, allow_blank: false, regexp: /.+@.+/
1195
+ end
1196
+ ```
1197
+
1198
+ See [#957](https://github.com/ruby-grape/grape/pull/957) for more information.
1199
+
1200
+ #### Replace error_response with error! in rescue_from blocks
1201
+
1202
+ Note: `error_response` is being deprecated, not removed.
1203
+
1204
+ ```ruby
1205
+ def error!(message, status = options[:default_status], headers = {}, backtrace = [])
1206
+ headers = { 'Content-Type' => content_type }.merge(headers)
1207
+ rack_response(format_message(message, backtrace), status, headers)
1208
+ end
1209
+ ```
1210
+
1211
+ For example,
1212
+
1213
+ ```
1214
+ error_response({ message: { message: 'No such page.', id: 'missing_page' }, status: 404, headers: { 'Content-Type' => 'api/error' })
1215
+ ```
1216
+
1217
+ becomes
1218
+
1219
+ ```
1220
+ error!({ message: 'No such page.', id: 'missing_page' }, 404, { 'Content-Type' => 'api/error' })
1221
+ ```
1222
+
1223
+ `error!` also supports just passing a message. `error!('Server error.')` and `format: :json` returns the following JSON response
1224
+
1225
+ ```
1226
+ { 'error': 'Server error.' }
1227
+ ```
1228
+
1229
+ with a status code of 500 and a Content Type of text/error.
1230
+
1231
+ Optionally, also replace `Rack::Response.new` with `error!.`
1232
+ The following are equivalent:
1233
+
1234
+ ```
1235
+ Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
1236
+ error!(e)
1237
+ ```
1238
+
1239
+ See [#889](https://github.com/ruby-grape/grape/issues/889) for more information.
1240
+
1241
+ #### Changes to routes when using `format`
1242
+
1243
+ Version 0.10.0 has introduced a change via [#809](https://github.com/ruby-grape/grape/pull/809) whereas routes no longer got file-type suffixes added if you declared a single API `format`. This has been reverted, it's now again possible to call API with proper suffix when single `format` is defined:
1244
+
1245
+ ```ruby
1246
+ class API < Grape::API
1247
+ format :json
1248
+
1249
+ get :hello do
1250
+ { hello: 'world' }
1251
+ end
1252
+ end
1253
+ ```
1254
+
1255
+ Will respond with JSON to `/hello` **and** `/hello.json`.
1256
+
1257
+ Will respond with 404 to `/hello.xml`, `/hello.txt` etc.
1258
+
1259
+ See the [#1001](https://github.com/ruby-grape/grape/pull/1001) and [#914](https://github.com/ruby-grape/grape/issues/914) for more info.
1260
+
1261
+ ### Upgrading to >= 0.11.0
1262
+
1263
+ #### Added Rack 1.6.0 support
1264
+
1265
+ Grape now supports, but doesn't require Rack 1.6.0. If you encounter an issue with parsing requests larger than 128KB, explictly require Rack 1.6.0 in your Gemfile.
1266
+
1267
+ ```ruby
1268
+ gem 'rack', '~> 1.6.0'
1269
+ ```
1270
+
1271
+ See [#559](https://github.com/ruby-grape/grape/issues/559) for more information.
1272
+
1273
+ #### Removed route_info
1274
+
1275
+ Key route_info is excluded from params.
1276
+
1277
+ See [#879](https://github.com/ruby-grape/grape/pull/879) for more information.
1278
+
1279
+
1280
+ #### Fix callbacks within a version block
1281
+
1282
+ Callbacks defined in a version block are only called for the routes defined in that block. This was a regression introduced in Grape 0.10.0, and is fixed in this version.
1283
+
1284
+ See [#901](https://github.com/ruby-grape/grape/pull/901) for more information.
1285
+
1286
+
1287
+ #### Make type of group of parameters required
1288
+
1289
+ Groups of parameters now require their type to be set explicitly as Array or Hash.
1290
+ Not setting the type now results in MissingGroupTypeError, unsupported type will raise UnsupportedTypeError.
1291
+
1292
+ See [#886](https://github.com/ruby-grape/grape/pull/886) for more information.
1293
+
1294
+ ### Upgrading to >= 0.10.1
1295
+
1296
+ #### Changes to `declared(params, include_missing: false)`
1297
+
1298
+ Attributes with `nil` values or with values that evaluate to `false` are no longer considered *missing* and will be returned when `include_missing` is set to `false`.
1299
+
1300
+ See [#864](https://github.com/ruby-grape/grape/pull/864) for more information.
1301
+
1302
+ ### Upgrading to >= 0.10.0
1303
+
1304
+ #### Changes to content-types
1305
+
1306
+ The following content-types have been removed:
1307
+
1308
+ * atom (application/atom+xml)
1309
+ * rss (application/rss+xml)
1310
+ * jsonapi (application/jsonapi)
1311
+
1312
+ This is because they have never been properly supported.
1313
+
1314
+ #### Changes to desc
1315
+
1316
+ New block syntax:
1317
+
1318
+ Former:
1319
+
1320
+ ```ruby
1321
+ desc "some descs",
1322
+ detail: 'more details',
1323
+ entity: API::Entities::Entity,
1324
+ params: API::Entities::Status.documentation,
1325
+ named: 'a name',
1326
+ headers: [XAuthToken: {
1327
+ description: 'Valdates your identity',
1328
+ required: true
1329
+ }
1330
+ get nil, http_codes: [
1331
+ [401, 'Unauthorized', API::Entities::BaseError],
1332
+ [404, 'not found', API::Entities::Error]
1333
+ ] do
1334
+ ```
1335
+
1336
+ Now:
1337
+
1338
+ ```ruby
1339
+ desc "some descs" do
1340
+ detail 'more details'
1341
+ params API::Entities::Status.documentation
1342
+ success API::Entities::Entity
1343
+ failure [
1344
+ [401, 'Unauthorized', API::Entities::BaseError],
1345
+ [404, 'not found', API::Entities::Error]
1346
+ ]
1347
+ named 'a name'
1348
+ headers [
1349
+ XAuthToken: {
1350
+ description: 'Valdates your identity',
1351
+ required: true
1352
+ },
1353
+ XOptionalHeader: {
1354
+ description: 'Not really needed',
1355
+ required: false
1356
+ }
1357
+ ]
1358
+ end
1359
+ ```
1360
+
1361
+ #### Changes to Route Options and Descriptions
1362
+
1363
+ A common hack to extend Grape with custom DSL methods was manipulating `@last_description`.
1364
+
1365
+ ``` ruby
1366
+ module Grape
1367
+ module Extensions
1368
+ module SortExtension
1369
+ def sort(value)
1370
+ @last_description ||= {}
1371
+ @last_description[:sort] ||= {}
1372
+ @last_description[:sort].merge! value
1373
+ value
1374
+ end
1375
+ end
1376
+
1377
+ Grape::API.extend self
1378
+ end
1379
+ end
1380
+ ```
1381
+
1382
+ You could access this value from within the API with `route.route_sort` or, more generally, via `env['api.endpoint'].options[:route_options][:sort]`.
1383
+
1384
+ This will no longer work, use the documented and supported `route_setting`.
1385
+
1386
+ ``` ruby
1387
+ module Grape
1388
+ module Extensions
1389
+ module SortExtension
1390
+ def sort(value)
1391
+ route_setting :sort, sort: value
1392
+ value
1393
+ end
1394
+ end
1395
+
1396
+ Grape::API.extend self
1397
+ end
1398
+ end
1399
+ ```
1400
+
1401
+ To retrieve this value at runtime from within an API, use `env['api.endpoint'].route_setting(:sort)` and when introspecting a mounted API, use `route.route_settings[:sort]`.
1402
+
1403
+ #### Accessing Class Variables from Helpers
1404
+
1405
+ It used to be possible to fetch an API class variable from a helper function. For example:
1406
+
1407
+ ```ruby
1408
+ @@static_variable = 42
1409
+
1410
+ helpers do
1411
+ def get_static_variable
1412
+ @@static_variable
1413
+ end
1414
+ end
1415
+
1416
+ get do
1417
+ get_static_variable
1418
+ end
1419
+ ```
1420
+
1421
+ This will no longer work. Use a class method instead of a helper.
1422
+
1423
+ ```ruby
1424
+ @@static_variable = 42
1425
+
1426
+ def self.get_static_variable
1427
+ @@static_variable
1428
+ end
1429
+
1430
+ get do
1431
+ get_static_variable
1432
+ end
1433
+ ```
1434
+
1435
+ For more information see [#836](https://github.com/ruby-grape/grape/issues/836).
1436
+
1437
+ #### Changes to Custom Validators
1438
+
1439
+ To implement a custom validator, you need to inherit from `Grape::Validations::Base` instead of `Grape::Validations::Validator`.
1440
+
1441
+ For more information see [Custom Validators](https://github.com/ruby-grape/grape#custom-validators) in the documentation.
1442
+
1443
+ #### Changes to Raising Grape::Exceptions::Validation
1444
+
1445
+ In previous versions raising `Grape::Exceptions::Validation` required a single `param`.
1446
+
1447
+ ```ruby
1448
+ raise Grape::Exceptions::Validation, param: :id, message_key: :presence
1449
+ ```
1450
+
1451
+ The `param` argument has been deprecated and is now an array of `params`, accepting multiple values.
1452
+
1453
+ ```ruby
1454
+ raise Grape::Exceptions::Validation, params: [:id], message_key: :presence
1455
+ ```
1456
+
1457
+ #### Changes to routes when using `format`
1458
+
1459
+ Routes will no longer get file-type suffixes added if you declare a single API `format`. For example,
1460
+
1461
+ ```ruby
1462
+ class API < Grape::API
1463
+ format :json
1464
+
1465
+ get :hello do
1466
+ { hello: 'world' }
1467
+ end
1468
+ end
1469
+ ```
1470
+
1471
+ Pre-0.10.0, this would respond with JSON to `/hello`, `/hello.json`, `/hello.xml`, `/hello.txt`, etc.
1472
+
1473
+ Now, this will only respond with JSON to `/hello`, but will be a 404 when trying to access `/hello.json`, `/hello.xml`, `/hello.txt`, etc.
1474
+
1475
+ If you declare further `content_type`s, this behavior will be circumvented. For example, the following API will respond with JSON to `/hello`, `/hello.json`, `/hello.xml`, `/hello.txt`, etc.
1476
+
1477
+ ```ruby
1478
+ class API < Grape::API
1479
+ format :json
1480
+ content_type :json, 'application/json'
1481
+
1482
+ get :hello do
1483
+ { hello: 'world' }
1484
+ end
1485
+ end
1486
+ ```
1487
+
1488
+ See the [the updated API Formats documentation](https://github.com/ruby-grape/grape#api-formats) and [#809](https://github.com/ruby-grape/grape/pull/809) for more info.
1489
+
1490
+ #### Changes to Evaluation of Permitted Parameter Values
1491
+
1492
+ Permitted and default parameter values are now only evaluated lazily for each request when declared as a proc. The following code would raise an error at startup time.
1493
+
1494
+ ```ruby
1495
+ params do
1496
+ optional :v, values: -> { [:x, :y] }, default: -> { :z }
1497
+ end
1498
+ ```
1499
+
1500
+ Remove the proc to get the previous behavior.
1501
+
1502
+ ```ruby
1503
+ params do
1504
+ optional :v, values: [:x, :y], default: :z
1505
+ end
1506
+ ```
1507
+
1508
+ See [#801](https://github.com/ruby-grape/grape/issues/801) for more information.
1509
+
1510
+ #### Changes to version
1511
+
1512
+ If version is used with a block, the callbacks defined within that version block are not scoped to that individual block. In other words, the callback would be inherited by all versions blocks that follow the first one e.g
1513
+
1514
+ ```ruby
1515
+ class API < Grape::API
1516
+ resource :foo do
1517
+ version 'v1', :using => :path do
1518
+ before do
1519
+ @output ||= 'hello1'
1520
+ end
1521
+ get '/' do
1522
+ @output += '-v1'
1523
+ end
1524
+ end
1525
+
1526
+ version 'v2', :using => :path do
1527
+ before do
1528
+ @output ||= 'hello2'
1529
+ end
1530
+ get '/:id' do
1531
+ @output += '-v2'
1532
+ end
1533
+ end
1534
+ end
1535
+ end
1536
+ ```
1537
+
1538
+ when making a API call `GET /foo/v2/1`, the API would set instance variable `@output` to `hello1-v2`
1539
+
1540
+ See [#898](https://github.com/ruby-grape/grape/issues/898) for more information.
1541
+
1542
+
1543
+ ### Upgrading to >= 0.9.0
1544
+
1545
+ #### Changes in Authentication
1546
+
1547
+ The following middleware classes have been removed:
1548
+
1549
+ * `Grape::Middleware::Auth::Basic`
1550
+ * `Grape::Middleware::Auth::Digest`
1551
+ * `Grape::Middleware::Auth::OAuth2`
1552
+
1553
+ When you use theses classes directly like:
1554
+
1555
+ ```ruby
1556
+ module API
1557
+ class Root < Grape::API
1558
+ class Protected < Grape::API
1559
+ use Grape::Middleware::Auth::OAuth2,
1560
+ token_class: 'AccessToken',
1561
+ parameter: %w(access_token api_key)
1562
+
1563
+ ```
1564
+
1565
+ you have to replace these classes.
1566
+
1567
+ As replacement can be used
1568
+
1569
+ * `Grape::Middleware::Auth::Basic` => [`Rack::Auth::Basic`](https://github.com/rack/rack/blob/master/lib/rack/auth/basic.rb)
1570
+ * `Grape::Middleware::Auth::Digest` => [`Rack::Auth::Digest::MD5`](https://github.com/rack/rack/blob/master/lib/rack/auth/digest/md5.rb)
1571
+ * `Grape::Middleware::Auth::OAuth2` => [warden-oauth2](https://github.com/opperator/warden-oauth2) or [rack-oauth2](https://github.com/nov/rack-oauth2)
1572
+
1573
+ If this is not possible you can extract the middleware files from [grape v0.7.0](https://github.com/ruby-grape/grape/tree/v0.7.0/lib/grape/middleware/auth) and host these files within your application
1574
+
1575
+ See [#703](https://github.com/ruby-grape/Grape/pull/703) for more information.
1576
+
1577
+ ### Upgrading to >= 0.7.0
1578
+
1579
+ #### Changes in Exception Handling
1580
+
1581
+ Assume you have the following exception classes defined.
1582
+
1583
+ ```ruby
1584
+ class ParentError < StandardError; end
1585
+ class ChildError < ParentError; end
1586
+ ```
1587
+
1588
+ In Grape <= 0.6.1, the `rescue_from` keyword only handled the exact exception being raised. The following code would rescue `ParentError`, but not `ChildError`.
1589
+
1590
+ ```ruby
1591
+ rescue_from ParentError do |e|
1592
+ # only rescue ParentError
1593
+ end
1594
+ ```
1595
+
1596
+ This made it impossible to rescue an exception hieararchy, which is a more sensible default. In Grape 0.7.0 or newer, both `ParentError` and `ChildError` are rescued.
1597
+
1598
+ ```ruby
1599
+ rescue_from ParentError do |e|
1600
+ # rescue both ParentError and ChildError
1601
+ end
1602
+ ```
1603
+
1604
+ To only rescue the base exception class, set `rescue_subclasses: false`.
1605
+
1606
+ ```ruby
1607
+ rescue_from ParentError, rescue_subclasses: false do |e|
1608
+ # only rescue ParentError
1609
+ end
1610
+ ```
1611
+
1612
+ See [#544](https://github.com/ruby-grape/grape/pull/544) for more information.
1613
+
1614
+
1615
+ #### Changes in the Default HTTP Status Code
1616
+
1617
+ In Grape <= 0.6.1, the default status code returned from `error!` was 403.
1618
+
1619
+ ```ruby
1620
+ error! "You may not reticulate this spline!" # yields HTTP error 403
1621
+ ```
1622
+
1623
+ This was a bad default value, since 403 means "Forbidden". Change any call to `error!` that does not specify a status code to specify one. The new default value is a more sensible default of 500, which is "Internal Server Error".
1624
+
1625
+ ```ruby
1626
+ error! "You may not reticulate this spline!", 403 # yields HTTP error 403
1627
+ ```
1628
+
1629
+ You may also use `default_error_status` to change the global default.
1630
+
1631
+ ```ruby
1632
+ default_error_status 400
1633
+ ```
1634
+
1635
+ See [#525](https://github.com/ruby-grape/Grape/pull/525) for more information.
1636
+
1637
+
1638
+ #### Changes in Parameter Declaration and Validation
1639
+
1640
+ In Grape <= 0.6.1, `group`, `optional` and `requires` keywords with a block accepted either an `Array` or a `Hash`.
1641
+
1642
+ ```ruby
1643
+ params do
1644
+ requires :id, type: Integer
1645
+ group :name do
1646
+ requires :first_name
1647
+ requires :last_name
1648
+ end
1649
+ end
1650
+ ```
1651
+
1652
+ This caused the ambiguity and unexpected errors described in [#543](https://github.com/ruby-grape/Grape/issues/543).
1653
+
1654
+ In Grape 0.7.0, the `group`, `optional` and `requires` keywords take an additional `type` attribute which defaults to `Array`. This means that without a `type` attribute, these nested parameters will no longer accept a single hash, only an array (of hashes).
1655
+
1656
+ Whereas in 0.6.1 the API above accepted the following json, it no longer does in 0.7.0.
1657
+
1658
+ ```json
1659
+ {
1660
+ "id": 1,
1661
+ "name": {
1662
+ "first_name": "John",
1663
+ "last_name" : "Doe"
1664
+ }
1665
+ }
1666
+ ```
1667
+
1668
+ The `params` block should now read as follows.
1669
+
1670
+ ```ruby
1671
+ params do
1672
+ requires :id, type: Integer
1673
+ requires :name, type: Hash do
1674
+ requires :first_name
1675
+ requires :last_name
1676
+ end
1677
+ end
1678
+ ```
1679
+
1680
+ See [#545](https://github.com/ruby-grape/Grape/pull/545) for more information.
1681
+
1682
+
1683
+ ### Upgrading to 0.6.0
1684
+
1685
+ In Grape <= 0.5.0, only the first validation error was raised and processing aborted. Validation errors are now collected and a single `Grape::Exceptions::ValidationErrors` exception is raised. You can access the collection of validation errors as `.errors`.
1686
+
1687
+ ```ruby
1688
+ rescue_from Grape::Exceptions::Validations do |e|
1689
+ Rack::Response.new({
1690
+ status: 422,
1691
+ message: e.message,
1692
+ errors: e.errors
1693
+ }.to_json, 422)
1694
+ end
1695
+ ```
1696
+
1697
+ For more information see [#462](https://github.com/ruby-grape/grape/issues/462).