grape 1.8.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -1
  3. data/README.md +377 -334
  4. data/UPGRADING.md +231 -6
  5. data/grape.gemspec +6 -10
  6. data/lib/grape/api/instance.rb +13 -10
  7. data/lib/grape/api.rb +17 -8
  8. data/lib/grape/content_types.rb +0 -2
  9. data/lib/grape/cookies.rb +2 -1
  10. data/lib/grape/dry_types.rb +0 -2
  11. data/lib/grape/dsl/desc.rb +23 -21
  12. data/lib/grape/dsl/headers.rb +1 -1
  13. data/lib/grape/dsl/inside_route.rb +47 -22
  14. data/lib/grape/dsl/parameters.rb +4 -3
  15. data/lib/grape/dsl/routing.rb +20 -4
  16. data/lib/grape/dsl/validations.rb +13 -0
  17. data/lib/grape/endpoint.rb +15 -10
  18. data/lib/grape/{util/env.rb → env.rb} +0 -5
  19. data/lib/grape/error_formatter/txt.rb +11 -10
  20. data/lib/grape/exceptions/base.rb +3 -3
  21. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  22. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  23. data/lib/grape/exceptions/validation.rb +0 -2
  24. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  25. data/lib/grape/exceptions/validation_errors.rb +1 -3
  26. data/lib/grape/extensions/hash.rb +5 -1
  27. data/lib/grape/http/headers.rb +18 -24
  28. data/lib/grape/{util/json.rb → json.rb} +1 -3
  29. data/lib/grape/locale/en.yml +3 -0
  30. data/lib/grape/middleware/auth/base.rb +0 -2
  31. data/lib/grape/middleware/auth/dsl.rb +0 -2
  32. data/lib/grape/middleware/auth/strategies.rb +1 -2
  33. data/lib/grape/middleware/base.rb +0 -2
  34. data/lib/grape/middleware/error.rb +55 -50
  35. data/lib/grape/middleware/formatter.rb +21 -18
  36. data/lib/grape/middleware/globals.rb +1 -3
  37. data/lib/grape/middleware/stack.rb +2 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
  39. data/lib/grape/middleware/versioner/header.rb +17 -163
  40. data/lib/grape/middleware/versioner/param.rb +2 -4
  41. data/lib/grape/middleware/versioner/path.rb +1 -3
  42. data/lib/grape/namespace.rb +3 -4
  43. data/lib/grape/path.rb +24 -29
  44. data/lib/grape/railtie.rb +9 -0
  45. data/lib/grape/request.rb +3 -5
  46. data/lib/grape/router/base_route.rb +39 -0
  47. data/lib/grape/router/greedy_route.rb +20 -0
  48. data/lib/grape/router/pattern.rb +39 -30
  49. data/lib/grape/router/route.rb +22 -59
  50. data/lib/grape/router.rb +30 -36
  51. data/lib/grape/util/accept/header.rb +19 -0
  52. data/lib/grape/util/accept_header_handler.rb +105 -0
  53. data/lib/grape/util/base_inheritable.rb +4 -4
  54. data/lib/grape/util/cache.rb +0 -3
  55. data/lib/grape/util/endpoint_configuration.rb +1 -1
  56. data/lib/grape/util/header.rb +13 -0
  57. data/lib/grape/util/inheritable_values.rb +0 -2
  58. data/lib/grape/util/lazy/block.rb +29 -0
  59. data/lib/grape/util/lazy/object.rb +45 -0
  60. data/lib/grape/util/lazy/value.rb +38 -0
  61. data/lib/grape/util/lazy/value_array.rb +21 -0
  62. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  63. data/lib/grape/util/lazy/value_hash.rb +21 -0
  64. data/lib/grape/util/media_type.rb +70 -0
  65. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  66. data/lib/grape/util/stackable_values.rb +1 -6
  67. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  68. data/lib/grape/validations/attributes_doc.rb +38 -36
  69. data/lib/grape/validations/contract_scope.rb +71 -0
  70. data/lib/grape/validations/params_scope.rb +10 -9
  71. data/lib/grape/validations/types/array_coercer.rb +0 -2
  72. data/lib/grape/validations/types/build_coercer.rb +69 -71
  73. data/lib/grape/validations/types/dry_type_coercer.rb +1 -11
  74. data/lib/grape/validations/types/json.rb +0 -2
  75. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  76. data/lib/grape/validations/types/set_coercer.rb +0 -3
  77. data/lib/grape/validations/types.rb +0 -3
  78. data/lib/grape/validations/validators/base.rb +2 -1
  79. data/lib/grape/validations/validators/default_validator.rb +5 -1
  80. data/lib/grape/validations/validators/length_validator.rb +42 -0
  81. data/lib/grape/validations/validators/values_validator.rb +8 -3
  82. data/lib/grape/validations.rb +3 -7
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  85. data/lib/grape.rb +38 -269
  86. metadata +33 -274
  87. data/lib/grape/eager_load.rb +0 -20
  88. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  89. data/lib/grape/router/attribute_translator.rb +0 -63
  90. data/lib/grape/util/lazy_block.rb +0 -27
  91. data/lib/grape/util/lazy_object.rb +0 -43
  92. data/lib/grape/util/lazy_value.rb +0 -91
  93. data/spec/grape/api/custom_validations_spec.rb +0 -213
  94. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  95. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  96. data/spec/grape/api/documentation_spec.rb +0 -59
  97. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  98. data/spec/grape/api/instance_spec.rb +0 -103
  99. data/spec/grape/api/invalid_format_spec.rb +0 -45
  100. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  101. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  102. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  103. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  104. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  105. data/spec/grape/api/recognize_path_spec.rb +0 -21
  106. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  107. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  108. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  109. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  110. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  111. data/spec/grape/api_remount_spec.rb +0 -509
  112. data/spec/grape/api_spec.rb +0 -4356
  113. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  114. data/spec/grape/dsl/desc_spec.rb +0 -98
  115. data/spec/grape/dsl/headers_spec.rb +0 -62
  116. data/spec/grape/dsl/helpers_spec.rb +0 -100
  117. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  118. data/spec/grape/dsl/logger_spec.rb +0 -24
  119. data/spec/grape/dsl/middleware_spec.rb +0 -60
  120. data/spec/grape/dsl/parameters_spec.rb +0 -180
  121. data/spec/grape/dsl/request_response_spec.rb +0 -225
  122. data/spec/grape/dsl/routing_spec.rb +0 -275
  123. data/spec/grape/dsl/settings_spec.rb +0 -261
  124. data/spec/grape/dsl/validations_spec.rb +0 -55
  125. data/spec/grape/endpoint/declared_spec.rb +0 -846
  126. data/spec/grape/endpoint_spec.rb +0 -1085
  127. data/spec/grape/entity_spec.rb +0 -336
  128. data/spec/grape/exceptions/base_spec.rb +0 -81
  129. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  130. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  131. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  132. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  133. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  134. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  135. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  136. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  137. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  138. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  139. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  140. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  141. data/spec/grape/exceptions/validation_spec.rb +0 -19
  142. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  143. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  144. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  145. data/spec/grape/grape_spec.rb +0 -9
  146. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  147. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  148. data/spec/grape/integration/rack_spec.rb +0 -51
  149. data/spec/grape/loading_spec.rb +0 -44
  150. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  151. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  152. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  153. data/spec/grape/middleware/base_spec.rb +0 -221
  154. data/spec/grape/middleware/error_spec.rb +0 -85
  155. data/spec/grape/middleware/exception_spec.rb +0 -294
  156. data/spec/grape/middleware/formatter_spec.rb +0 -461
  157. data/spec/grape/middleware/globals_spec.rb +0 -30
  158. data/spec/grape/middleware/stack_spec.rb +0 -155
  159. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  160. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  161. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  162. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  163. data/spec/grape/middleware/versioner_spec.rb +0 -21
  164. data/spec/grape/named_api_spec.rb +0 -19
  165. data/spec/grape/parser_spec.rb +0 -86
  166. data/spec/grape/path_spec.rb +0 -252
  167. data/spec/grape/presenters/presenter_spec.rb +0 -71
  168. data/spec/grape/request_spec.rb +0 -126
  169. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  170. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  171. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  172. data/spec/grape/util/stackable_values_spec.rb +0 -128
  173. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  174. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  175. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  176. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  177. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  178. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  179. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  180. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  181. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  182. data/spec/grape/validations/types_spec.rb +0 -111
  183. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  184. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  185. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  186. data/spec/grape/validations/validators/base_spec.rb +0 -38
  187. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  188. data/spec/grape/validations/validators/default_spec.rb +0 -463
  189. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  190. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  191. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  192. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  193. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  194. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  195. data/spec/grape/validations/validators/values_spec.rb +0 -733
  196. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  197. data/spec/grape/validations_spec.rb +0 -2030
  198. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  199. data/spec/integration/multi_json/json_spec.rb +0 -7
  200. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  201. data/spec/shared/deprecated_class_examples.rb +0 -16
  202. data/spec/shared/versioning_examples.rb +0 -215
  203. data/spec/spec_helper.rb +0 -52
  204. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  205. data/spec/support/chunks.rb +0 -14
  206. data/spec/support/content_type_helpers.rb +0 -15
  207. data/spec/support/endpoint_faker.rb +0 -25
  208. data/spec/support/file_streamer.rb +0 -13
  209. data/spec/support/integer_helpers.rb +0 -13
  210. data/spec/support/versioned_helpers.rb +0 -55
data/README.md CHANGED
@@ -15,24 +15,22 @@
15
15
  - [Grape for Enterprise](#grape-for-enterprise)
16
16
  - [Installation](#installation)
17
17
  - [Basic Usage](#basic-usage)
18
+ - [Rails 7.1](#rails-71)
18
19
  - [Mounting](#mounting)
19
20
  - [All](#all)
20
21
  - [Rack](#rack)
21
- - [ActiveRecord without Rails](#activerecord-without-rails)
22
- - [Rails 4](#rails-4)
23
- - [Rails 5+](#rails-5)
24
22
  - [Alongside Sinatra (or other frameworks)](#alongside-sinatra-or-other-frameworks)
25
23
  - [Rails](#rails)
26
- - [Rails < 5.2](#rails--52)
27
- - [Rails 6.0](#rails-60)
24
+ - [Zeitwerk](#zeitwerk)
28
25
  - [Modules](#modules)
29
26
  - [Remounting](#remounting)
30
27
  - [Mount Configuration](#mount-configuration)
31
28
  - [Versioning](#versioning)
32
- - [Path](#path)
33
- - [Header](#header)
34
- - [Accept-Version Header](#accept-version-header)
35
- - [Param](#param)
29
+ - [Strategies](#strategies)
30
+ - [Path](#path)
31
+ - [Header](#header)
32
+ - [Accept-Version Header](#accept-version-header)
33
+ - [Param](#param)
36
34
  - [Describing Methods](#describing-methods)
37
35
  - [Configuration](#configuration)
38
36
  - [Parameters](#parameters)
@@ -41,6 +39,7 @@
41
39
  - [Include Parent Namespaces](#include-parent-namespaces)
42
40
  - [Include Missing](#include-missing)
43
41
  - [Evaluate Given](#evaluate-given)
42
+ - [Parameter Precedence](#parameter-precedence)
44
43
  - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
45
44
  - [Supported Parameter Types](#supported-parameter-types)
46
45
  - [Integer/Fixnum and Coercions](#integerfixnum-and-coercions)
@@ -57,6 +56,7 @@
57
56
  - [values](#values)
58
57
  - [except_values](#except_values)
59
58
  - [same_as](#same_as)
59
+ - [length](#length)
60
60
  - [regexp](#regexp)
61
61
  - [mutually_exclusive](#mutually_exclusive)
62
62
  - [exactly_one_of](#exactly_one_of)
@@ -70,6 +70,7 @@
70
70
  - [Custom Validation messages](#custom-validation-messages)
71
71
  - [presence, allow_blank, values, regexp](#presence-allow_blank-values-regexp)
72
72
  - [same_as](#same_as-1)
73
+ - [length](#length-1)
73
74
  - [all_or_none_of](#all_or_none_of-1)
74
75
  - [mutually_exclusive](#mutually_exclusive-1)
75
76
  - [exactly_one_of](#exactly_one_of-1)
@@ -79,6 +80,7 @@
79
80
  - [Pass symbols for i18n translations](#pass-symbols-for-i18n-translations)
80
81
  - [Overriding Attribute Names](#overriding-attribute-names)
81
82
  - [With Default](#with-default)
83
+ - [Using dry-validation or dry-schema](#using-dry-validation-or-dry-schema)
82
84
  - [Headers](#headers)
83
85
  - [Request](#request)
84
86
  - [Header Case Handling](#header-case-handling)
@@ -99,7 +101,6 @@
99
101
  - [Rescuing exceptions inside namespaces](#rescuing-exceptions-inside-namespaces)
100
102
  - [Unrescuable Exceptions](#unrescuable-exceptions)
101
103
  - [Exceptions that should be rescued explicitly](#exceptions-that-should-be-rescued-explicitly)
102
- - [Rails 3.x](#rails-3x)
103
104
  - [Logging](#logging)
104
105
  - [API Formats](#api-formats)
105
106
  - [JSONP](#jsonp)
@@ -114,12 +115,13 @@
114
115
  - [Active Model Serializers](#active-model-serializers)
115
116
  - [Sending Raw or No Data](#sending-raw-or-no-data)
116
117
  - [Authentication](#authentication)
117
- - [Basic and Digest Auth](#basic-and-digest-auth)
118
+ - [Basic Auth](#basic-auth)
118
119
  - [Register custom middleware for authentication](#register-custom-middleware-for-authentication)
119
120
  - [Describing and Inspecting an API](#describing-and-inspecting-an-api)
120
121
  - [Current Route and Endpoint](#current-route-and-endpoint)
121
122
  - [Before, After and Finally](#before-after-and-finally)
122
123
  - [Anchoring](#anchoring)
124
+ - [Instance Variables](#instance-variables)
123
125
  - [Using Custom Middleware](#using-custom-middleware)
124
126
  - [Grape Middleware](#grape-middleware)
125
127
  - [Rails Middleware](#rails-middleware)
@@ -151,15 +153,11 @@
151
153
 
152
154
  ## What is Grape?
153
155
 
154
- Grape is a REST-like API framework for Ruby. It's designed to run on Rack
155
- or complement existing web application frameworks such as Rails and Sinatra by
156
- providing a simple DSL to easily develop RESTful APIs. It has built-in support
157
- for common conventions, including multiple formats, subdomain/prefix restriction,
158
- content negotiation, versioning and much more.
156
+ Grape is a REST-like API framework for Ruby. It's designed to run on Rack or complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily develop RESTful APIs. It has built-in support for common conventions, including multiple formats, subdomain/prefix restriction, content negotiation, versioning and much more.
159
157
 
160
158
  ## Stable Release
161
159
 
162
- You're reading the documentation for the stable release of Grape, **1.8.0**.
160
+ You're reading the documentation for the stable release of Grape, **2.1.0**.
163
161
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
164
162
 
165
163
  ## Project Resources
@@ -177,7 +175,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support
177
175
 
178
176
  ## Installation
179
177
 
180
- Ruby 2.4 or newer is required.
178
+ Ruby 2.7 or newer is required.
181
179
 
182
180
  Grape is available as a gem, to install it run:
183
181
 
@@ -186,8 +184,7 @@ Grape is available as a gem, to install it run:
186
184
  ## Basic Usage
187
185
 
188
186
  Grape APIs are Rack applications that are created by subclassing `Grape::API`.
189
- Below is a simple example showing some of the more common features of Grape in
190
- the context of recreating parts of the Twitter API.
187
+ Below is a simple example showing some of the more common features of Grape in the context of recreating parts of the Twitter API.
191
188
 
192
189
  ```ruby
193
190
  module Twitter
@@ -266,6 +263,10 @@ module Twitter
266
263
  end
267
264
  ```
268
265
 
266
+ ## Rails 7.1
267
+
268
+ Grape's [deprecator](https://api.rubyonrails.org/v7.1.0/classes/ActiveSupport/Deprecation.html) will be added to your application's deprecators [automatically](lib/grape/railtie.rb) as `:grape`, so that your application's configuration can be applied to it.
269
+
269
270
  ## Mounting
270
271
 
271
272
  ### All
@@ -281,8 +282,7 @@ This can be added to your `config.ru` (if using rackup), `application.rb` (if us
281
282
 
282
283
  ### Rack
283
284
 
284
- The above sample creates a Rack application that can be run from a rackup `config.ru` file
285
- with `rackup`:
285
+ The above sample creates a Rack application that can be run from a rackup `config.ru` file with `rackup`:
286
286
 
287
287
  ```ruby
288
288
  run Twitter::API
@@ -306,32 +306,9 @@ And would respond to the following routes:
306
306
 
307
307
  Grape will also automatically respond to HEAD and OPTIONS for all GET, and just OPTIONS for all other routes.
308
308
 
309
- ### ActiveRecord without Rails
310
-
311
- If you want to use ActiveRecord within Grape, you will need to make sure that ActiveRecord's connection pool
312
- is handled correctly.
313
-
314
- #### Rails 4
315
-
316
- The easiest way to achieve that is by using ActiveRecord's `ConnectionManagement` middleware in your
317
- `config.ru` before mounting Grape, e.g.:
318
-
319
- ```ruby
320
- use ActiveRecord::ConnectionAdapters::ConnectionManagement
321
- ```
322
-
323
- #### Rails 5+
324
-
325
- Use [otr-activerecord](https://github.com/jhollinger/otr-activerecord) as follows:
326
-
327
- ```ruby
328
- use OTR::ActiveRecord::ConnectionManagement
329
- ```
330
-
331
309
  ### Alongside Sinatra (or other frameworks)
332
310
 
333
- If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using
334
- `Rack::Cascade`:
311
+ If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using `Rack::Cascade`:
335
312
 
336
313
  ```ruby
337
314
  # Example config.ru
@@ -367,21 +344,8 @@ Modify `config/routes`:
367
344
  ```ruby
368
345
  mount Twitter::API => '/'
369
346
  ```
370
-
371
- #### Rails < 5.2
372
-
373
- Modify `application.rb`:
374
-
375
- ```ruby
376
- config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
377
- config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
378
- ```
379
-
380
- See [below](#reloading-api-changes-in-development) for additional code that enables reloading of API changes in development.
381
-
382
- #### Rails 6.0
383
-
384
- For Rails versions greater than 6.0.0.beta2, `Zeitwerk` autoloader is the default for CRuby. By default `Zeitwerk` inflects `api` as `Api` instead of `API`. To make our example work, you need to uncomment the lines at the bottom of `config/initializers/inflections.rb`, and add `API` as an acronym:
347
+ #### Zeitwerk
348
+ Rails's default autoloader is `Zeitwerk`. By default, it inflects `api` as `Api` instead of `API`. To make our example work, you need to uncomment the lines at the bottom of `config/initializers/inflections.rb`, and add `API` as an acronym:
385
349
 
386
350
  ```ruby
387
351
  ActiveSupport::Inflector.inflections(:en) do |inflect|
@@ -391,8 +355,7 @@ end
391
355
 
392
356
  ### Modules
393
357
 
394
- You can mount multiple API implementations inside another one. These don't have to be
395
- different versions, but may be components of the same API.
358
+ You can mount multiple API implementations inside another one. These don't have to be different versions, but may be components of the same API.
396
359
 
397
360
  ```ruby
398
361
  class Twitter::API < Grape::API
@@ -409,7 +372,7 @@ class Twitter::API < Grape::API
409
372
  end
410
373
  ```
411
374
 
412
- Keep in mind such declarations as `before/after/rescue_from` must be placed before `mount` in a case where they should be inherited.
375
+ Declarations as `before/after/rescue_from` can be placed before or after `mount`. In any case they will be inherited.
413
376
 
414
377
  ```ruby
415
378
  class Twitter::API < Grape::API
@@ -417,8 +380,20 @@ class Twitter::API < Grape::API
417
380
  header 'X-Base-Header', 'will be defined for all APIs that are mounted below'
418
381
  end
419
382
 
383
+ rescue_from :all do
384
+ error!({ "error" => "Internal Server Error" }, 500)
385
+ end
386
+
420
387
  mount Twitter::Users
421
388
  mount Twitter::Search
389
+
390
+ after do
391
+ clean_cache!
392
+ end
393
+
394
+ rescue_from ZeroDivisionError do
395
+ error!({ "error" => "Not found" }, 404)
396
+ end
422
397
  end
423
398
  ```
424
399
 
@@ -549,10 +524,69 @@ end
549
524
 
550
525
  ## Versioning
551
526
 
552
- There are four strategies in which clients can reach your API's endpoints: `:path`,
553
- `:header`, `:accept_version_header` and `:param`. The default strategy is `:path`.
527
+ You have the option to provide various versions of your API by establishing a separate `Grape::API` class for each offered version and then integrating them into a primary `Grape::API` class. Ensure that newer versions are mounted before older ones. The default approach to versioning directs the request to the subsequent Rack middleware if a specific version is not found.
528
+
529
+ ```ruby
530
+ require 'v1'
531
+ require 'v2'
532
+ require 'v3'
533
+ class App < Grape::API
534
+ mount V3
535
+ mount V2
536
+ mount V1
537
+ end
538
+ ```
554
539
 
555
- ### Path
540
+ To maintain the same endpoints from earlier API versions without rewriting them, you can indicate multiple versions within the previous API versions.
541
+
542
+ ```ruby
543
+ class V1 < Grape::API
544
+ version 'v1', 'v2', 'v3'
545
+
546
+ get '/foo' do
547
+ # your code for GET /foo
548
+ end
549
+
550
+ get '/other' do
551
+ # your code for GET /other
552
+ end
553
+ end
554
+
555
+ class V2 < Grape::API
556
+ version 'v2', 'v3'
557
+
558
+ get '/var' do
559
+ # your code for GET /var
560
+ end
561
+ end
562
+
563
+ class V3 < Grape::API
564
+ version 'v3'
565
+
566
+ get '/foo' do
567
+ # your new code for GET /foo
568
+ end
569
+ end
570
+ ```
571
+
572
+ Using the example provided, the subsequent endpoints will be accessible across various versions:
573
+
574
+ ```shell
575
+ GET /v1/foo
576
+ GET /v1/other
577
+ GET /v2/foo # => Same behavior as v1
578
+ GET /v2/other # => Same behavior as v1
579
+ GET /v2/var # => New endpoint not available in v1
580
+ GET /v3/foo # => Different behavior to v1 and v2
581
+ GET /v3/other # => Same behavior as v1 and v2
582
+ GET /v3/var # => Same behavior as v2
583
+ ```
584
+
585
+ There are four strategies in which clients can reach your API's endpoints: `:path`, `:header`, `:accept_version_header` and `:param`. The default strategy is `:path`.
586
+
587
+ ### Strategies
588
+
589
+ #### Path
556
590
 
557
591
  ```ruby
558
592
  version 'v1', using: :path
@@ -562,7 +596,7 @@ Using this versioning strategy, clients should pass the desired version in the U
562
596
 
563
597
  curl http://localhost:9292/v1/statuses/public_timeline
564
598
 
565
- ### Header
599
+ #### Header
566
600
 
567
601
  ```ruby
568
602
  version 'v1', using: :header, vendor: 'twitter'
@@ -580,16 +614,15 @@ Using this versioning strategy, clients should pass the desired version in the H
580
614
 
581
615
  curl -H Accept:application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
582
616
 
583
- By default, the first matching version is used when no `Accept` header is
584
- supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
585
- one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
586
- is returned when no correct `Accept` header is supplied.
617
+ By default, the first matching version is used when no `Accept` header is supplied. This behavior is similar to routing in Rails. To circumvent this default behavior, one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error is returned when no correct `Accept` header is supplied.
587
618
 
588
- When an invalid `Accept` header is supplied, a `406 Not Acceptable` error is returned if the `:cascade`
589
- option is set to `false`. Otherwise a `404 Not Found` error is returned by Rack if no other route
590
- matches.
619
+ When an invalid `Accept` header is supplied, a `406 Not Acceptable` error is returned if the `:cascade` option is set to `false`. Otherwise a `404 Not Found` error is returned by Rack if no other route matches.
591
620
 
592
- ### Accept-Version Header
621
+ Grape will evaluate the relative quality preference included in Accept headers and default to a quality of 1.0 when omitted. In the following example a Grape API that supports XML and JSON in that order will return JSON:
622
+
623
+ curl -H "Accept: text/xml;q=0.8, application/json;q=0.9" localhost:1234/resource
624
+
625
+ #### Accept-Version Header
593
626
 
594
627
  ```ruby
595
628
  version 'v1', using: :accept_version_header
@@ -599,20 +632,15 @@ Using this versioning strategy, clients should pass the desired version in the H
599
632
 
600
633
  curl -H "Accept-Version:v1" http://localhost:9292/statuses/public_timeline
601
634
 
602
- By default, the first matching version is used when no `Accept-Version` header is
603
- supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
604
- one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
605
- is returned when no correct `Accept` header is supplied and the `:cascade` option is set to `false`.
606
- Otherwise a `404 Not Found` error is returned by Rack if no other route matches.
635
+ By default, the first matching version is used when no `Accept-Version` header is supplied. This behavior is similar to routing in Rails. To circumvent this default behavior, one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error is returned when no correct `Accept` header is supplied and the `:cascade` option is set to `false`. Otherwise a `404 Not Found` error is returned by Rack if no other route matches.
607
636
 
608
- ### Param
637
+ #### Param
609
638
 
610
639
  ```ruby
611
640
  version 'v1', using: :param
612
641
  ```
613
642
 
614
- Using this versioning strategy, clients should pass the desired version as a request parameter,
615
- either in the URL query string or in the request body.
643
+ Using this versioning strategy, clients should pass the desired version as a request parameter, either in the URL query string or in the request body.
616
644
 
617
645
  curl http://localhost:9292/statuses/public_timeline?apiver=v1
618
646
 
@@ -703,13 +731,11 @@ API.configure do |config|
703
731
  end
704
732
  ```
705
733
 
706
- This will be available inside the API with `configuration`, as if it were
707
- [mount configuration](#mount-configuration).
734
+ This will be available inside the API with `configuration`, as if it were [mount configuration](#mount-configuration).
708
735
 
709
736
  ## Parameters
710
737
 
711
- Request parameters are available through the `params` hash object. This includes `GET`, `POST`
712
- and `PUT` parameters, along with any named parameters you specify in your route strings.
738
+ Request parameters are available through the `params` hash object. This includes `GET`, `POST` and `PUT` parameters, along with any named parameters you specify in your route strings.
713
739
 
714
740
  ```ruby
715
741
  get :public_timeline do
@@ -717,8 +743,7 @@ get :public_timeline do
717
743
  end
718
744
  ```
719
745
 
720
- Parameters are automatically populated from the request body on `POST` and `PUT` for form input, JSON and
721
- XML content-types.
746
+ Parameters are automatically populated from the request body on `POST` and `PUT` for form input, JSON and XML content-types.
722
747
 
723
748
  The request:
724
749
 
@@ -1057,8 +1082,7 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
1057
1082
  }
1058
1083
  ````
1059
1084
 
1060
- Note that an attribute with a `nil` value is not considered *missing* and will also be returned
1061
- when `include_missing` is set to `false`:
1085
+ Note that an attribute with a `nil` value is not considered *missing* and will also be returned when `include_missing` is set to `false`:
1062
1086
 
1063
1087
  **Request**
1064
1088
 
@@ -1176,6 +1200,35 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/child -d '{"chil
1176
1200
  }
1177
1201
  ````
1178
1202
 
1203
+ ### Parameter Precedence
1204
+
1205
+ Using `route_param` takes higher precedence over a regular parameter defined with same name:
1206
+
1207
+ ```ruby
1208
+ params do
1209
+ requires :foo, type: String
1210
+ end
1211
+ route_param :foo do
1212
+ get do
1213
+ { value: params[:foo] }
1214
+ end
1215
+ end
1216
+ ```
1217
+
1218
+ **Request**
1219
+
1220
+ ```bash
1221
+ curl -X POST -H "Content-Type: application/json" localhost:9292/bar -d '{"foo": "baz"}'
1222
+ ```
1223
+
1224
+ **Response**
1225
+
1226
+ ```json
1227
+ {
1228
+ "value": "bar"
1229
+ }
1230
+ ```
1231
+
1179
1232
  ## Parameter Validation and Coercion
1180
1233
 
1181
1234
  You can define validations and coercion options for your parameters using a `params` block.
@@ -1197,8 +1250,7 @@ put ':id' do
1197
1250
  end
1198
1251
  ```
1199
1252
 
1200
- When a type is specified an implicit validation is done after the coercion to ensure
1201
- the output type is the one declared.
1253
+ When a type is specified an implicit validation is done after the coercion to ensure the output type is the one declared.
1202
1254
 
1203
1255
  Optional parameters can have a default value.
1204
1256
 
@@ -1210,9 +1262,7 @@ params do
1210
1262
  end
1211
1263
  ```
1212
1264
 
1213
- Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same
1214
- number for each call to the endpoint of this `params` block. To have the default evaluate
1215
- lazily with each request use a lambda, like `:random_number` above.
1265
+ Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same number for each call to the endpoint of this `params` block. To have the default evaluate lazily with each request use a lambda, like `:random_number` above.
1216
1266
 
1217
1267
  Note that default values will be passed through to any validation options specified.
1218
1268
  The following example will always fail if `:color` is not explicitly provided.
@@ -1231,6 +1281,15 @@ params do
1231
1281
  end
1232
1282
  ```
1233
1283
 
1284
+ You can use the value of one parameter as the default value of some other parameter. In this case, if the `primary_color` parameter is not provided, it will have the same value as the `color` one. If both of them not provided, both of them will have `blue` value.
1285
+
1286
+ ```ruby
1287
+ params do
1288
+ optional :color, type: String, default: 'blue'
1289
+ optional :primary_color, type: String, default: -> (params) { params[:color] }
1290
+ end
1291
+ ```
1292
+
1234
1293
  ### Supported Parameter Types
1235
1294
 
1236
1295
  The following are all valid types, supported out of the box by Grape:
@@ -1272,12 +1331,7 @@ get '/int' integers: { int: '45' }
1272
1331
 
1273
1332
  ### Custom Types and Coercions
1274
1333
 
1275
- Aside from the default set of supported types listed above, any class can be
1276
- used as a type as long as an explicit coercion method is supplied. If the type
1277
- implements a class-level `parse` method, Grape will use it automatically.
1278
- This method must take one string argument and return an instance of the correct
1279
- type, or return an instance of `Grape::Types::InvalidValue` which optionally
1280
- accepts a message to be returned in the response.
1334
+ Aside from the default set of supported types listed above, any class can be used as a type as long as an explicit coercion method is supplied. If the type implements a class-level `parse` method, Grape will use it automatically. This method must take one string argument and return an instance of the correct type, or return an instance of `Grape::Types::InvalidValue` which optionally accepts a message to be returned in the response.
1281
1335
 
1282
1336
  ```ruby
1283
1337
  class Color
@@ -1287,7 +1341,7 @@ class Color
1287
1341
  end
1288
1342
 
1289
1343
  def self.parse(value)
1290
- return new(value) if %w[blue red green]).include?(value)
1344
+ return new(value) if %w[blue red green].include?(value)
1291
1345
 
1292
1346
  Grape::Types::InvalidValue.new('Unsupported color')
1293
1347
  end
@@ -1305,10 +1359,7 @@ get '/stuff' do
1305
1359
  end
1306
1360
  ```
1307
1361
 
1308
- Alternatively, a custom coercion method may be supplied for any type of parameter
1309
- using `coerce_with`. Any class or object may be given that implements a `parse` or
1310
- `call` method, in that order of precedence. The method must accept a single string
1311
- parameter, and the return value must match the given `type`.
1362
+ Alternatively, a custom coercion method may be supplied for any type of parameter using `coerce_with`. Any class or object may be given that implements a `parse` or `call` method, in that order of precedence. The method must accept a single string parameter, and the return value must match the given `type`.
1312
1363
 
1313
1364
  ```ruby
1314
1365
  params do
@@ -1332,9 +1383,7 @@ params do
1332
1383
  end
1333
1384
  ```
1334
1385
 
1335
- Grape will assert that coerced values match the given `type`, and will reject the request
1336
- if they do not. To override this behaviour, custom types may implement a `parsed?` method
1337
- that should accept a single argument and return `true` if the value passes type validation.
1386
+ Grape will assert that coerced values match the given `type`, and will reject the request if they do not. To override this behaviour, custom types may implement a `parsed?` method that should accept a single argument and return `true` if the value passes type validation.
1338
1387
 
1339
1388
  ```ruby
1340
1389
  class SecureUri
@@ -1369,9 +1418,7 @@ end
1369
1418
 
1370
1419
  ### First-Class `JSON` Types
1371
1420
 
1372
- Grape supports complex parameters given as JSON-formatted strings using the special `type: JSON`
1373
- declaration. JSON objects and arrays of objects are accepted equally, with nested validation
1374
- rules applied to all objects in either case:
1421
+ Grape supports complex parameters given as JSON-formatted strings using the special `type: JSON` declaration. JSON objects and arrays of objects are accepted equally, with nested validation rules applied to all objects in either case:
1375
1422
 
1376
1423
  ```ruby
1377
1424
  params do
@@ -1390,8 +1437,7 @@ client.get('/', json: '{"int":4}') # => HTTP 400
1390
1437
  client.get('/', json: '[{"int":4}]') # => HTTP 400
1391
1438
  ```
1392
1439
 
1393
- Additionally `type: Array[JSON]` may be used, which explicitly marks the parameter as an array
1394
- of objects. If a single object is supplied it will be wrapped.
1440
+ Additionally `type: Array[JSON]` may be used, which explicitly marks the parameter as an array of objects. If a single object is supplied it will be wrapped.
1395
1441
 
1396
1442
  ```ruby
1397
1443
  params do
@@ -1403,8 +1449,7 @@ get '/' do
1403
1449
  params[:json].each { |obj| ... } # always works
1404
1450
  end
1405
1451
  ```
1406
- For stricter control over the type of JSON structure which may be supplied,
1407
- use `type: Array, coerce_with: JSON` or `type: Hash, coerce_with: JSON`.
1452
+ For stricter control over the type of JSON structure which may be supplied, use `type: Array, coerce_with: JSON` or `type: Hash, coerce_with: JSON`.
1408
1453
 
1409
1454
  ### Multiple Allowed Types
1410
1455
 
@@ -1423,8 +1468,7 @@ client.get('/', status_code: 300) # => 300
1423
1468
  client.get('/', status_code: %w(404 NOT FOUND)) # => [404, "NOT", "FOUND"]
1424
1469
  ```
1425
1470
 
1426
- As a special case, variant-member-type collections may also be declared, by
1427
- passing a `Set` or `Array` with more than one member to `type`:
1471
+ As a special case, variant-member-type collections may also be declared, by passing a `Set` or `Array` with more than one member to `type`:
1428
1472
 
1429
1473
  ```ruby
1430
1474
  params do
@@ -1440,11 +1484,8 @@ client.get('/', status_codes: %w(1 two)) # => [1, "two"]
1440
1484
  ### Validation of Nested Parameters
1441
1485
 
1442
1486
  Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
1443
- In the [above example](#parameter-validation-and-coercion), this means `params[:media][:url]` is required along with `params[:id]`,
1444
- and `params[:audio][:format]` is required only if `params[:audio]` is present.
1445
- With a block, `group`, `requires` and `optional` accept an additional option `type` which can
1446
- be either `Array` or `Hash`, and defaults to `Array`. Depending on the value, the nested
1447
- parameters will be treated either as values of a hash or as values of hashes in an array.
1487
+ In the [above example](#parameter-validation-and-coercion), this means `params[:media][:url]` is required along with `params[:id]`, and `params[:audio][:format]` is required only if `params[:audio]` is present.
1488
+ With a block, `group`, `requires` and `optional` accept an additional option `type` which can be either `Array` or `Hash`, and defaults to `Array`. Depending on the value, the nested parameters will be treated either as values of a hash or as values of hashes in an array.
1448
1489
 
1449
1490
  ```ruby
1450
1491
  params do
@@ -1462,9 +1503,7 @@ end
1462
1503
 
1463
1504
  ### Dependent Parameters
1464
1505
 
1465
- Suppose some of your parameters are only relevant if another parameter is given;
1466
- Grape allows you to express this relationship through the `given` method in your
1467
- parameters block, like so:
1506
+ Suppose some of your parameters are only relevant if another parameter is given; Grape allows you to express this relationship through the `given` method in your parameters block, like so:
1468
1507
 
1469
1508
  ```ruby
1470
1509
  params do
@@ -1503,31 +1542,45 @@ Note: param in `given` should be the renamed one. In the example, it should be `
1503
1542
 
1504
1543
  ### Group Options
1505
1544
 
1506
- Parameters options can be grouped. It can be useful if you want to extract
1507
- common validation or types for several parameters. The example below presents a
1508
- typical case when parameters share common options.
1545
+ Parameters options can be grouped. It can be useful if you want to extract common validation or types for several parameters.
1546
+ Within these groups, individual parameters can extend or selectively override the common settings, allowing you to maintain the defaults at the group level while still applying parameter-specific rules where necessary.
1547
+
1548
+ The example below presents a typical case when parameters share common options.
1509
1549
 
1510
1550
  ```ruby
1511
1551
  params do
1512
- requires :first_name, type: String, regexp: /w+/, desc: 'First name'
1513
- requires :middle_name, type: String, regexp: /w+/, desc: 'Middle name'
1514
- requires :last_name, type: String, regexp: /w+/, desc: 'Last name'
1552
+ requires :first_name, type: String, regexp: /w+/, desc: 'First name', documentation: { in: 'body' }
1553
+ optional :middle_name, type: String, regexp: /w+/, desc: 'Middle name', documentation: { in: 'body', x: { nullable: true } }
1554
+ requires :last_name, type: String, regexp: /w+/, desc: 'Last name', documentation: { in: 'body' }
1515
1555
  end
1516
1556
  ```
1517
1557
 
1518
- Grape allows you to present the same logic through the `with` method in your
1519
- parameters block, like so:
1558
+ Grape allows you to present the same logic through the `with` method in your parameters block, like so:
1520
1559
 
1521
1560
  ```ruby
1522
1561
  params do
1523
- with(type: String, regexp: /w+/) do
1562
+ with(type: String, regexp: /w+/, documentation: { in: 'body' }) do
1524
1563
  requires :first_name, desc: 'First name'
1525
- requires :middle_name, desc: 'Middle name'
1564
+ optional :middle_name, desc: 'Middle name', documentation: { x: { nullable: true } }
1526
1565
  requires :last_name, desc: 'Last name'
1527
1566
  end
1528
1567
  end
1529
1568
  ```
1530
1569
 
1570
+ You can organize settings into layers using nested `with' blocks. Each layer can use, add to, or change the settings of the layer above it. This helps to keep complex parameters organized and consistent, while still allowing for specific customizations to be made.
1571
+
1572
+ ```ruby
1573
+ params do
1574
+ with(documentation: { in: 'body' }) do # Applies documentation to all nested parameters
1575
+ with(type: String, regexp: /\w+/) do # Applies type and validation to names
1576
+ requires :first_name, desc: 'First name'
1577
+ requires :last_name, desc: 'Last name'
1578
+ end
1579
+ optional :age, type: Integer, desc: 'Age', documentation: { x: { nullable: true } } # Specific settings for 'age'
1580
+ end
1581
+ end
1582
+ ```
1583
+
1531
1584
  ### Renaming
1532
1585
 
1533
1586
  You can rename parameters using `as`, which can be useful when refactoring existing APIs:
@@ -1550,13 +1603,9 @@ The value passed to `as` will be the key when calling `declared(params)`.
1550
1603
 
1551
1604
  #### `allow_blank`
1552
1605
 
1553
- Parameters can be defined as `allow_blank`, ensuring that they contain a value. By default, `requires`
1554
- only validates that a parameter was sent in the request, regardless its value. With `allow_blank: false`,
1555
- empty values or whitespace only values are invalid.
1606
+ Parameters can be defined as `allow_blank`, ensuring that they contain a value. By default, `requires` only validates that a parameter was sent in the request, regardless its value. With `allow_blank: false`, empty values or whitespace only values are invalid.
1556
1607
 
1557
- `allow_blank` can be combined with both `requires` and `optional`. If the parameter is required, it has to contain
1558
- a value. If it's optional, it's possible to not send it in the request, but if it's being sent, it has to have
1559
- some value, and not an empty string/only whitespaces.
1608
+ `allow_blank` can be combined with both `requires` and `optional`. If the parameter is required, it has to contain a value. If it's optional, it's possible to not send it in the request, but if it's being sent, it has to have some value, and not an empty string/only whitespaces.
1560
1609
 
1561
1610
 
1562
1611
  ```ruby
@@ -1593,7 +1642,7 @@ Note endless ranges are also supported with ActiveSupport >= 6.0, but they requi
1593
1642
  ```ruby
1594
1643
  params do
1595
1644
  requires :minimum, type: Integer, values: 10..
1596
- optional :maximum, type: Integer, values: ..10
1645
+ optional :maximum, type: Integer, values: ..10
1597
1646
  end
1598
1647
  ```
1599
1648
 
@@ -1607,11 +1656,9 @@ end
1607
1656
  ```
1608
1657
 
1609
1658
  The `:values` option can also be supplied with a `Proc`, evaluated lazily with each request.
1610
- If the Proc has arity zero (i.e. it takes no arguments) it is expected to return either a list
1611
- or a range which will then be used to validate the parameter.
1659
+ If the Proc has arity zero (i.e. it takes no arguments) it is expected to return either a list or a range which will then be used to validate the parameter.
1612
1660
 
1613
- For example, given a status model you may want to restrict by hashtags that you have
1614
- previously defined in the `HashTag` model.
1661
+ For example, given a status model you may want to restrict by hashtags that you have previously defined in the `HashTag` model.
1615
1662
 
1616
1663
  ```ruby
1617
1664
  params do
@@ -1619,10 +1666,7 @@ params do
1619
1666
  end
1620
1667
  ```
1621
1668
 
1622
- Alternatively, a Proc with arity one (i.e. taking one argument) can be used to explicitly validate
1623
- each parameter value. In that case, the Proc is expected to return a truthy value if the parameter
1624
- value is valid. The parameter will be considered invalid if the Proc returns a falsy value or if it
1625
- raises a StandardError.
1669
+ Alternatively, a Proc with arity one (i.e. taking one argument) can be used to explicitly validate each parameter value. In that case, the Proc is expected to return a truthy value if the parameter value is valid. The parameter will be considered invalid if the Proc returns a falsy value or if it raises a StandardError.
1626
1670
 
1627
1671
  ```ruby
1628
1672
  params do
@@ -1644,9 +1688,7 @@ end
1644
1688
 
1645
1689
  Parameters can be restricted from having a specific set of values with the `:except_values` option.
1646
1690
 
1647
- The `except_values` validator behaves similarly to the `values` validator in that it accepts either
1648
- an Array, a Range, or a Proc. Unlike the `values` validator, however, `except_values` only accepts
1649
- Procs with arity zero.
1691
+ The `except_values` validator behaves similarly to the `values` validator in that it accepts either an Array, a Range, or a Proc. Unlike the `values` validator, however, `except_values` only accepts Procs with arity zero.
1650
1692
 
1651
1693
  ```ruby
1652
1694
  params do
@@ -1667,11 +1709,23 @@ params do
1667
1709
  end
1668
1710
  ```
1669
1711
 
1712
+ #### `length`
1713
+
1714
+ Parameters with types that support `#length` method can be restricted to have a specific length with the `:length` option.
1715
+
1716
+ The validator accepts `:min` or `:max` or both options to validate that the value of the parameter is within the given limits.
1717
+
1718
+ ```ruby
1719
+ params do
1720
+ requires :str, type: String, length: { min: 3 }
1721
+ requires :list, type: [Integer], length: { min: 3, max: 5 }
1722
+ requires :hash, type: Hash, length: { max: 5 }
1723
+ end
1724
+ ```
1725
+
1670
1726
  #### `regexp`
1671
1727
 
1672
- Parameters can be restricted to match a specific regular expression with the `:regexp` option. If the value
1673
- does not match the regular expression an error will be returned. Note that this is true for both `requires`
1674
- and `optional` parameters.
1728
+ Parameters can be restricted to match a specific regular expression with the `:regexp` option. If the value does not match the regular expression an error will be returned. Note that this is true for both `requires` and `optional` parameters.
1675
1729
 
1676
1730
  ```ruby
1677
1731
  params do
@@ -1806,8 +1860,7 @@ namespace :statuses do
1806
1860
  end
1807
1861
  ```
1808
1862
 
1809
- The `namespace` method has a number of aliases, including: `group`, `resource`,
1810
- `resources`, and `segment`. Use whichever reads the best for your API.
1863
+ The `namespace` method has a number of aliases, including: `group`, `resource`, `resources`, and `segment`. Use whichever reads the best for your API.
1811
1864
 
1812
1865
  You can conveniently define a route parameter as a namespace using `route_param`.
1813
1866
 
@@ -1962,8 +2015,7 @@ end
1962
2015
 
1963
2016
  ### I18n
1964
2017
 
1965
- Grape supports I18n for parameter-related error messages, but will fallback to English if
1966
- translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
2018
+ Grape supports I18n for parameter-related error messages, but will fallback to English if translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
1967
2019
 
1968
2020
  In case your app enforces available locales only and :en is not included in your available locales, Grape cannot fall back to English and will return the translation key for the error message. To avoid this behaviour, either provide a translation for your default locale or add :en to your available locales.
1969
2021
 
@@ -1988,6 +2040,15 @@ params do
1988
2040
  end
1989
2041
  ```
1990
2042
 
2043
+ #### `length`
2044
+
2045
+ ```ruby
2046
+ params do
2047
+ requires :str, type: String, length: { min: 5, message: 'str is expected to be atleast 5 characters long' }
2048
+ requires :list, type: [Integer], length: { min: 2, max: 3, message: 'list is expected to have between 2 and 3 elements' }
2049
+ end
2050
+ ```
2051
+
1991
2052
  #### `all_or_none_of`
1992
2053
 
1993
2054
  ```ruby
@@ -2096,6 +2157,40 @@ params do
2096
2157
  end
2097
2158
  ```
2098
2159
 
2160
+ ### Using `dry-validation` or `dry-schema`
2161
+
2162
+ As an alternative to the `params` DSL described above, you can use a schema or `dry-validation` contract to describe an endpoint's parameters. This can be especially useful if you use the above already in some other parts of your application. If not, you'll need to add `dry-validation` or `dry-schema` to your `Gemfile`.
2163
+
2164
+ Then call `contract` with a contract or schema defined previously:
2165
+
2166
+ ```rb
2167
+ CreateOrdersSchema = Dry::Schema.Params do
2168
+ required(:orders).array(:hash) do
2169
+ required(:name).filled(:string)
2170
+ optional(:volume).maybe(:integer, lt?: 9)
2171
+ end
2172
+ end
2173
+
2174
+ # ...
2175
+
2176
+ contract CreateOrdersSchema
2177
+ ```
2178
+
2179
+ or with a block, using the [schema definition syntax](https://dry-rb.org/gems/dry-schema/1.13/#quick-start):
2180
+
2181
+ ```rb
2182
+ contract do
2183
+ required(:orders).array(:hash) do
2184
+ required(:name).filled(:string)
2185
+ optional(:volume).maybe(:integer, lt?: 9)
2186
+ end
2187
+ end
2188
+ ```
2189
+
2190
+ The latter will define a coercing schema (`Dry::Schema.Params`). When using the former approach, it's up to you to decide whether the input will need coercing.
2191
+
2192
+ The `params` and `contract` declarations can also be used together in the same API, e.g. to describe different parts of a nested namespace for an endpoint.
2193
+
2099
2194
  ## Headers
2100
2195
 
2101
2196
  ### Request
@@ -2123,8 +2218,9 @@ curl -H "secret_PassWord: swordfish" ...
2123
2218
 
2124
2219
  The header name will have been normalized for you.
2125
2220
 
2126
- - In the `header` helper names will be coerced into a capitalized kebab case.
2127
- - In the `env` collection they appear in all uppercase, in snake case, and prefixed with 'HTTP_'.
2221
+ - In the `header` helper names will be coerced into a downcased kebab case as `secret-password` if using Rack 3.
2222
+ - In the `header` helper names will be coerced into a capitalized kebab case as `Secret-PassWord` if using Rack < 3.
2223
+ - In the `env` collection they appear in all uppercase, in snake case, and prefixed with 'HTTP_' as `HTTP_SECRET_PASSWORD`
2128
2224
 
2129
2225
  The header name will have been normalized per HTTP standards defined in [RFC2616 Section 4.2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) regardless of what is being sent by a client.
2130
2226
 
@@ -2194,8 +2290,7 @@ namespace ':id' do
2194
2290
  end
2195
2291
  ```
2196
2292
 
2197
- Optionally, you can define requirements for your named route parameters using regular
2198
- expressions on namespace or endpoint. The route will match only if all requirements are met.
2293
+ Optionally, you can define requirements for your named route parameters using regular expressions on namespace or endpoint. The route will match only if all requirements are met.
2199
2294
 
2200
2295
  ```ruby
2201
2296
  get ':id', requirements: { id: /[0-9]*/ } do
@@ -2213,8 +2308,7 @@ end
2213
2308
 
2214
2309
  ## Helpers
2215
2310
 
2216
- You can define helper methods that your endpoints can use with the `helpers`
2217
- macro by either giving a block or an array of modules.
2311
+ You can define helper methods that your endpoints can use with the `helpers` macro by either giving a block or an array of modules.
2218
2312
 
2219
2313
  ```ruby
2220
2314
  module StatusHelpers
@@ -2453,11 +2547,36 @@ end
2453
2547
  API.recognize_path '/statuses'
2454
2548
  ```
2455
2549
 
2550
+ Since version `2.1.0`, the `recognize_path` method takes into account the parameters type to determine which endpoint should match with given path.
2551
+
2552
+ ```ruby
2553
+ class Books < Grape::API
2554
+ resource :books do
2555
+ route_param :id, type: Integer do
2556
+ # GET /books/:id
2557
+ get do
2558
+ #...
2559
+ end
2560
+ end
2561
+
2562
+ resource :share do
2563
+ # POST /books/share
2564
+ post do
2565
+ # ....
2566
+ end
2567
+ end
2568
+ end
2569
+ end
2570
+
2571
+ API.recognize_path '/books/1' # => /books/:id
2572
+ API.recognize_path '/books/share' # => /books/share
2573
+ API.recognize_path '/books/other' # => nil
2574
+ ```
2575
+
2576
+
2456
2577
  ## Allowed Methods
2457
2578
 
2458
- When you add a `GET` route for a resource, a route for the `HEAD`
2459
- method will also be added automatically. You can disable this
2460
- behavior with `do_not_route_head!`.
2579
+ When you add a `GET` route for a resource, a route for the `HEAD` method will also be added automatically. You can disable this behavior with `do_not_route_head!`.
2461
2580
 
2462
2581
  ``` ruby
2463
2582
  class API < Grape::API
@@ -2469,11 +2588,7 @@ class API < Grape::API
2469
2588
  end
2470
2589
  ```
2471
2590
 
2472
- When you add a route for a resource, a route for the `OPTIONS`
2473
- method will also be added. The response to an OPTIONS request will
2474
- include an "Allow" header listing the supported methods. If the resource
2475
- has `before` and `after` callbacks they will be executed, but no other callbacks will
2476
- run.
2591
+ When you add a route for a resource, a route for the `OPTIONS` method will also be added. The response to an OPTIONS request will include an "Allow" header listing the supported methods. If the resource has `before` and `after` callbacks they will be executed, but no other callbacks will run.
2477
2592
 
2478
2593
  ```ruby
2479
2594
  class API < Grape::API
@@ -2502,10 +2617,7 @@ curl -v -X OPTIONS http://localhost:3000/rt_count
2502
2617
 
2503
2618
  You can disable this behavior with `do_not_route_options!`.
2504
2619
 
2505
- If a request for a resource is made with an unsupported HTTP method, an
2506
- HTTP 405 (Method Not Allowed) response will be returned. If the resource
2507
- has `before` callbacks they will be executed, but no other callbacks will
2508
- run.
2620
+ If a request for a resource is made with an unsupported HTTP method, an HTTP 405 (Method Not Allowed) response will be returned. If the resource has `before` callbacks they will be executed, but no other callbacks will run.
2509
2621
 
2510
2622
  ``` shell
2511
2623
  curl -X DELETE -v http://localhost:3000/rt_count/
@@ -2531,8 +2643,7 @@ Anything that responds to `#to_s` can be given as a first argument to `error!`.
2531
2643
  error! :not_found, 404
2532
2644
  ```
2533
2645
 
2534
- You can also return JSON formatted objects by raising error! and passing a hash
2535
- instead of a message.
2646
+ You can also return JSON formatted objects by raising error! and passing a hash instead of a message.
2536
2647
 
2537
2648
  ```ruby
2538
2649
  error!({ error: 'unexpected error', detail: 'missing widget' }, 500)
@@ -2597,8 +2708,7 @@ route :any, '*path' do
2597
2708
  end
2598
2709
  ```
2599
2710
 
2600
- It is very crucial to __define this endpoint at the very end of your API__, as it
2601
- literally accepts every request.
2711
+ It is very crucial to __define this endpoint at the very end of your API__, as it literally accepts every request.
2602
2712
 
2603
2713
  ## Exception Handling
2604
2714
 
@@ -2840,33 +2950,11 @@ Any exception that is not subclass of `StandardError` should be rescued explicit
2840
2950
  Usually it is not a case for an application logic as such errors point to problems in Ruby runtime.
2841
2951
  This is following [standard recommendations for exceptions handling](https://ruby-doc.org/core/Exception.html).
2842
2952
 
2843
- ### Rails 3.x
2844
-
2845
- When mounted inside containers, such as Rails 3.x, errors such as "404 Not Found" or
2846
- "406 Not Acceptable" will likely be handled and rendered by Rails handlers. For instance,
2847
- accessing a nonexistent route "/api/foo" raises a 404, which inside rails will ultimately
2848
- be translated to an `ActionController::RoutingError`, which most likely will get rendered
2849
- to a HTML error page.
2850
-
2851
- Most APIs will enjoy preventing downstream handlers from handling errors. You may set the
2852
- `:cascade` option to `false` for the entire API or separately on specific `version` definitions,
2853
- which will remove the `X-Cascade: true` header from API responses.
2854
-
2855
- ```ruby
2856
- cascade false
2857
- ```
2858
-
2859
- ```ruby
2860
- version 'v1', using: :header, vendor: 'twitter', cascade: false
2861
- ```
2862
-
2863
2953
  ## Logging
2864
2954
 
2865
- `Grape::API` provides a `logger` method which by default will return an instance of the `Logger`
2866
- class from Ruby's standard library.
2955
+ `Grape::API` provides a `logger` method which by default will return an instance of the `Logger` class from Ruby's standard library.
2867
2956
 
2868
- To log messages from within an endpoint, you need to define a helper to make the logger
2869
- available in the endpoint context.
2957
+ To log messages from within an endpoint, you need to define a helper to make the logger available in the endpoint context.
2870
2958
 
2871
2959
  ```ruby
2872
2960
  class API < Grape::API
@@ -2915,9 +3003,7 @@ For similar to Rails request logging try the [grape_logging](https://github.com/
2915
3003
 
2916
3004
  ## API Formats
2917
3005
 
2918
- Your API can declare which content-types to support by using `content_type`. If you do not specify any, Grape will support
2919
- _XML_, _JSON_, _BINARY_, and _TXT_ content-types. The default format is `:txt`; you can change this with `default_format`.
2920
- Essentially, the two APIs below are equivalent.
3006
+ Your API can declare which content-types to support by using `content_type`. If you do not specify any, Grape will support _XML_, _JSON_, _BINARY_, and _TXT_ content-types. The default format is `:txt`; you can change this with `default_format`. Essentially, the two APIs below are equivalent.
2921
3007
 
2922
3008
  ```ruby
2923
3009
  class Twitter::API < Grape::API
@@ -2936,9 +3022,7 @@ class Twitter::API < Grape::API
2936
3022
  end
2937
3023
  ```
2938
3024
 
2939
- If you declare any `content_type` whatsoever, the Grape defaults will be overridden. For example, the following API will only
2940
- support the `:xml` and `:rss` content-types, but not `:txt`, `:json`, or `:binary`. Importantly, this means the `:txt`
2941
- default format is not supported! So, make sure to set a new `default_format`.
3025
+ If you declare any `content_type` whatsoever, the Grape defaults will be overridden. For example, the following API will only support the `:xml` and `:rss` content-types, but not `:txt`, `:json`, or `:binary`. Importantly, this means the `:txt` default format is not supported! So, make sure to set a new `default_format`.
2942
3026
 
2943
3027
  ```ruby
2944
3028
  class Twitter::API < Grape::API
@@ -2949,8 +3033,7 @@ class Twitter::API < Grape::API
2949
3033
  end
2950
3034
  ```
2951
3035
 
2952
- Serialization takes place automatically. For example, you do not have to call `to_json` in each JSON API endpoint
2953
- implementation. The response format (and thus the automatic serialization) is determined in the following order:
3036
+ Serialization takes place automatically. For example, you do not have to call `to_json` in each JSON API endpoint implementation. The response format (and thus the automatic serialization) is determined in the following order:
2954
3037
  * Use the file extension, if specified. If the file is .json, choose the JSON format.
2955
3038
  * Use the value of the `format` parameter in the query string, if specified.
2956
3039
  * Use the format set by the `format` option, if specified.
@@ -2973,18 +3056,13 @@ class MultipleFormatAPI < Grape::API
2973
3056
  end
2974
3057
  ```
2975
3058
 
2976
- * `GET /hello` (with an `Accept: */*` header) does not have an extension or a `format` parameter, so it will respond with
2977
- JSON (the default format).
3059
+ * `GET /hello` (with an `Accept: */*` header) does not have an extension or a `format` parameter, so it will respond with JSON (the default format).
2978
3060
  * `GET /hello.xml` has a recognized extension, so it will respond with XML.
2979
3061
  * `GET /hello?format=xml` has a recognized `format` parameter, so it will respond with XML.
2980
- * `GET /hello.xml?format=json` has a recognized extension (which takes precedence over the `format` parameter), so it will
2981
- respond with XML.
2982
- * `GET /hello.xls` (with an `Accept: */*` header) has an extension, but that extension is not recognized, so it will respond
2983
- with JSON (the default format).
2984
- * `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header
2985
- corresponds to a recognized format, so it will respond with XML.
2986
- * `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header,
2987
- so it will respond with JSON (the default format).
3062
+ * `GET /hello.xml?format=json` has a recognized extension (which takes precedence over the `format` parameter), so it will respond with XML.
3063
+ * `GET /hello.xls` (with an `Accept: */*` header) has an extension, but that extension is not recognized, so it will respond with JSON (the default format).
3064
+ * `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header corresponds to a recognized format, so it will respond with XML.
3065
+ * `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header, so it will respond with JSON (the default format).
2988
3066
 
2989
3067
  You can override this process explicitly by specifying `env['api.format']` in the API itself.
2990
3068
  For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
@@ -3001,8 +3079,7 @@ class Twitter::API < Grape::API
3001
3079
  end
3002
3080
  ```
3003
3081
 
3004
- You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file
3005
- extensions other than specified in `format`. For example, consider the following API.
3082
+ You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file extensions other than specified in `format`. For example, consider the following API.
3006
3083
 
3007
3084
  ```ruby
3008
3085
  class SingleFormatAPI < Grape::API
@@ -3017,14 +3094,10 @@ end
3017
3094
  * `GET /hello` will respond with JSON.
3018
3095
  * `GET /hello.json` will respond with JSON.
3019
3096
  * `GET /hello.xml`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code.
3020
- * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter
3021
- is not supported.
3022
- * `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a
3023
- recognized content-type from the headers and JSON is the effective default.
3097
+ * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter is not supported.
3098
+ * `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a recognized content-type from the headers and JSON is the effective default.
3024
3099
 
3025
- The formats apply to parsing, too. The following API will only respond to the JSON content-type and will not parse any other
3026
- input than `application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`, `multipart/related` and
3027
- `multipart/mixed`. All other requests will fail with an HTTP 406 error code.
3100
+ The formats apply to parsing, too. The following API will only respond to the JSON content-type and will not parse any other input than `application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`, `multipart/related` and `multipart/mixed`. All other requests will fail with an HTTP 406 error code.
3028
3101
 
3029
3102
  ```ruby
3030
3103
  class Twitter::API < Grape::API
@@ -3080,23 +3153,18 @@ end
3080
3153
  Built-in formatters are the following.
3081
3154
 
3082
3155
  * `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
3083
- * `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
3156
+ * `:xml`: use object's `to_xml` when available, usually via `MultiXml`
3084
3157
  * `:txt`: use object's `to_txt` when available, otherwise `to_s`
3085
3158
  * `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`
3086
3159
  * `:binary`: data will be returned "as is"
3087
3160
 
3088
- If a body is present in a request to an API, with a Content-Type header value that is of an unsupported type a
3089
- "415 Unsupported Media Type" error code will be returned by Grape.
3161
+ If a body is present in a request to an API, with a Content-Type header value that is of an unsupported type a "415 Unsupported Media Type" error code will be returned by Grape.
3090
3162
 
3091
- Response statuses that indicate no content as defined by [Rack](https://github.com/rack)
3092
- [here](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
3093
- will bypass serialization and the body entity - though there should be none -
3094
- will not be modified.
3163
+ Response statuses that indicate no content as defined by [Rack](https://github.com/rack) [here](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567) will bypass serialization and the body entity - though there should be none - will not be modified.
3095
3164
 
3096
3165
  ### JSONP
3097
3166
 
3098
- Grape supports JSONP via [Rack::JSONP](https://github.com/rack/rack-contrib), part of the
3099
- [rack-contrib](https://github.com/rack/rack-contrib) gem. Add `rack-contrib` to your `Gemfile`.
3167
+ Grape supports JSONP via [Rack::JSONP](https://github.com/rack/rack-contrib), part of the [rack-contrib](https://github.com/rack/rack-contrib) gem. Add `rack-contrib` to your `Gemfile`.
3100
3168
 
3101
3169
  ```ruby
3102
3170
  require 'rack/contrib'
@@ -3112,9 +3180,7 @@ end
3112
3180
 
3113
3181
  ### CORS
3114
3182
 
3115
- Grape supports CORS via [Rack::CORS](https://github.com/cyu/rack-cors), part of the
3116
- [rack-cors](https://github.com/cyu/rack-cors) gem. Add `rack-cors` to your `Gemfile`,
3117
- then use the middleware in your config.ru file.
3183
+ Grape supports CORS via [Rack::CORS](https://github.com/cyu/rack-cors), part of the [rack-cors](https://github.com/cyu/rack-cors) gem. Add `rack-cors` to your `Gemfile`, then use the middleware in your config.ru file.
3118
3184
 
3119
3185
  ```ruby
3120
3186
  require 'rack/cors'
@@ -3132,8 +3198,7 @@ run Twitter::API
3132
3198
 
3133
3199
  ## Content-type
3134
3200
 
3135
- Content-type is set by the formatter. You can override the content-type of the response at runtime
3136
- by setting the `Content-Type` header.
3201
+ Content-type is set by the formatter. You can override the content-type of the response at runtime by setting the `Content-Type` header.
3137
3202
 
3138
3203
  ```ruby
3139
3204
  class API < Grape::API
@@ -3146,16 +3211,12 @@ end
3146
3211
 
3147
3212
  ## API Data Formats
3148
3213
 
3149
- Grape accepts and parses input data sent with the POST and PUT methods as described in the Parameters
3150
- section above. It also supports custom data formats. You must declare additional content-types via
3151
- `content_type` and optionally supply a parser via `parser` unless a parser is already available within
3152
- Grape to enable a custom format. Such a parser can be a function or a class.
3214
+ Grape accepts and parses input data sent with the POST and PUT methods as described in the Parameters section above. It also supports custom data formats. You must declare additional content-types via `content_type` and optionally supply a parser via `parser` unless a parser is already available within Grape to enable a custom format. Such a parser can be a function or a class.
3153
3215
 
3154
3216
  With a parser, parsed data is available "as-is" in `env['api.request.body']`.
3155
3217
  Without a parser, data is available "as-is" and in `env['api.request.input']`.
3156
3218
 
3157
- The following example is a trivial parser that will assign any input with the "text/custom" content-type
3158
- to `:value`. The parameter will be available via `params[:value]` inside the API call.
3219
+ The following example is a trivial parser that will assign any input with the "text/custom" content-type to `:value`. The parameter will be available via `params[:value]` inside the API call.
3159
3220
 
3160
3221
  ```ruby
3161
3222
  module CustomParser
@@ -3189,9 +3250,7 @@ Grape uses `JSON` and `ActiveSupport::XmlMini` for JSON and XML parsing by defau
3189
3250
 
3190
3251
  ## RESTful Model Representations
3191
3252
 
3192
- Grape supports a range of ways to present your data with some help from a generic `present` method,
3193
- which accepts two arguments: the object to be presented and the options associated with it. The options
3194
- hash may include `:with`, which defines the entity to expose.
3253
+ Grape supports a range of ways to present your data with some help from a generic `present` method, which accepts two arguments: the object to be presented and the options associated with it. The options hash may include `:with`, which defines the entity to expose.
3195
3254
 
3196
3255
  ### Grape Entities
3197
3256
 
@@ -3270,8 +3329,7 @@ The response will be
3270
3329
  }
3271
3330
  ```
3272
3331
 
3273
- In addition to separately organizing entities, it may be useful to put them as namespaced
3274
- classes underneath the model they represent.
3332
+ In addition to separately organizing entities, it may be useful to put them as namespaced classes underneath the model they represent.
3275
3333
 
3276
3334
  ```ruby
3277
3335
  class Status
@@ -3285,11 +3343,7 @@ class Status
3285
3343
  end
3286
3344
  ```
3287
3345
 
3288
- If you organize your entities this way, Grape will automatically detect the `Entity` class and
3289
- use it to present your models. In this example, if you added `present Status.new` to your endpoint,
3290
- Grape will automatically detect that there is a `Status::Entity` class and use that as the
3291
- representative entity. This can still be overridden by using the `:with` option or an explicit
3292
- `represents` call.
3346
+ If you organize your entities this way, Grape will automatically detect the `Entity` class and use it to present your models. In this example, if you added `present Status.new` to your endpoint, Grape will automatically detect that there is a `Status::Entity` class and use that as the representative entity. This can still be overridden by using the `:with` option or an explicit `represents` call.
3293
3347
 
3294
3348
  You can present `hash` with `Grape::Presenters::Presenter` to keep things consistent.
3295
3349
 
@@ -3322,15 +3376,11 @@ You can use [Roar](https://github.com/apotonick/roar) to render HAL or Collectio
3322
3376
 
3323
3377
  ### Rabl
3324
3378
 
3325
- You can use [Rabl](https://github.com/nesquena/rabl) templates with the help of the
3326
- [grape-rabl](https://github.com/ruby-grape/grape-rabl) gem, which defines a custom Grape Rabl
3327
- formatter.
3379
+ You can use [Rabl](https://github.com/nesquena/rabl) templates with the help of the [grape-rabl](https://github.com/ruby-grape/grape-rabl) gem, which defines a custom Grape Rabl formatter.
3328
3380
 
3329
3381
  ### Active Model Serializers
3330
3382
 
3331
- You can use [Active Model Serializers](https://github.com/rails-api/active_model_serializers) serializers with the help of the
3332
- [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers) gem, which defines a custom Grape AMS
3333
- formatter.
3383
+ You can use [Active Model Serializers](https://github.com/rails-api/active_model_serializers) serializers with the help of the [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers) gem, which defines a custom Grape AMS formatter.
3334
3384
 
3335
3385
  ## Sending Raw or No Data
3336
3386
 
@@ -3370,9 +3420,7 @@ class API < Grape::API
3370
3420
  end
3371
3421
  ```
3372
3422
 
3373
- You can also set the response to a file with `sendfile`. This works with the
3374
- [Rack::Sendfile](https://www.rubydoc.info/gems/rack/Rack/Sendfile) middleware to optimally send
3375
- the file through your web server software.
3423
+ You can also set the response to a file with `sendfile`. This works with the [Rack::Sendfile](https://www.rubydoc.info/gems/rack/Rack/Sendfile) middleware to optimally send the file through your web server software.
3376
3424
 
3377
3425
  ```ruby
3378
3426
  class API < Grape::API
@@ -3414,11 +3462,9 @@ end
3414
3462
 
3415
3463
  ## Authentication
3416
3464
 
3417
- ### Basic and Digest Auth
3465
+ ### Basic Auth
3418
3466
 
3419
- Grape has built-in Basic and Digest authentication (the given `block`
3420
- is executed in the context of the current `Endpoint`). Authentication
3421
- applies to the current namespace and any children, but not parents.
3467
+ Grape has built-in Basic authentication (the given `block` is executed in the context of the current `Endpoint`). Authentication applies to the current namespace and any children, but not parents.
3422
3468
 
3423
3469
  ```ruby
3424
3470
  http_basic do |username, password|
@@ -3427,32 +3473,15 @@ http_basic do |username, password|
3427
3473
  end
3428
3474
  ```
3429
3475
 
3430
- Digest auth supports clear-text passwords and password hashes.
3431
-
3432
- ```ruby
3433
- http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
3434
- # lookup the user's password here
3435
- end
3436
- ```
3437
-
3438
- ```ruby
3439
- http_digest(realm: { realm: 'Test Api', opaque: 'app secret', passwords_hashed: true }) do |username|
3440
- # lookup the user's password hash here
3441
- end
3442
- ```
3443
-
3444
3476
  ### Register custom middleware for authentication
3445
3477
 
3446
- Grape can use custom Middleware for authentication. How to implement these
3447
- Middleware have a look at `Rack::Auth::Basic` or similar implementations.
3448
-
3478
+ Grape can use custom Middleware for authentication. How to implement these Middleware have a look at `Rack::Auth::Basic` or similar implementations.
3449
3479
 
3450
3480
  For registering a Middleware you need the following options:
3451
3481
 
3452
3482
  * `label` - the name for your authenticator to use it later
3453
3483
  * `MiddlewareClass` - the MiddlewareClass to use for authentication
3454
- * `option_lookup_proc` - A Proc with one Argument to lookup the options at
3455
- runtime (return value is an `Array` as Parameter for the Middleware).
3484
+ * `option_lookup_proc` - A Proc with one Argument to lookup the options at runtime (return value is an `Array` as Parameter for the Middleware).
3456
3485
 
3457
3486
  Example:
3458
3487
 
@@ -3476,7 +3505,7 @@ You can access the controller params, headers, and helpers through the context w
3476
3505
 
3477
3506
  Grape routes can be reflected at runtime. This can notably be useful for generating documentation.
3478
3507
 
3479
- Grape exposes arrays of API versions and compiled routes. Each route contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`, `route_path` and `route_params`. You can add custom route settings to the route metadata with `route_setting`.
3508
+ Grape exposes arrays of API versions and compiled routes. Each route contains a `prefix`, `version`, `namespace`, `method` and `params`. You can add custom route settings to the route metadata with `route_setting`.
3480
3509
 
3481
3510
  ```ruby
3482
3511
  class TwitterAPI < Grape::API
@@ -3499,7 +3528,7 @@ TwitterAPI::routes[0].description # => 'Includes custom settings.'
3499
3528
  TwitterAPI::routes[0].settings[:custom] # => { key: 'value' }
3500
3529
  ```
3501
3530
 
3502
- Note that `Route#route_xyz` methods have been deprecated since 0.15.0.
3531
+ Note that `Route#route_xyz` methods have been deprecated since 0.15.0 and removed since 2.0.1.
3503
3532
 
3504
3533
  Please use `Route#xyz` instead.
3505
3534
 
@@ -3519,15 +3548,12 @@ class MyAPI < Grape::API
3519
3548
  requires :id, type: Integer, desc: 'Identity.'
3520
3549
  end
3521
3550
  get 'params/:id' do
3522
- route.route_params[params[:id]] # yields the parameter description
3551
+ route.params[params[:id]] # yields the parameter description
3523
3552
  end
3524
3553
  end
3525
3554
  ```
3526
3555
 
3527
- The current endpoint responding to the request is `self` within the API block
3528
- or `env['api.endpoint']` elsewhere. The endpoint has some interesting properties,
3529
- such as `source` which gives you access to the original code block of the API
3530
- implementation. This can be particularly useful for building a logger middleware.
3556
+ The current endpoint responding to the request is `self` within the API block or `env['api.endpoint']` elsewhere. The endpoint has some interesting properties, such as `source` which gives you access to the original code block of the API implementation. This can be particularly useful for building a logger middleware.
3531
3557
 
3532
3558
  ```ruby
3533
3559
  class ApiLogger < Grape::Middleware::Base
@@ -3541,10 +3567,8 @@ end
3541
3567
 
3542
3568
  ## Before, After and Finally
3543
3569
 
3544
- Blocks can be executed before or after every API call, using `before`, `after`,
3545
- `before_validation` and `after_validation`.
3546
- If the API fails the `after` call will not be triggered, if you need code to execute for sure
3547
- use the `finally`.
3570
+ Blocks can be executed before or after every API call, using `before`, `after`, `before_validation` and `after_validation`.
3571
+ If the API fails the `after` call will not be triggered, if you need code to execute for sure use the `finally`.
3548
3572
 
3549
3573
  Before and after callbacks execute in the following order:
3550
3574
 
@@ -3558,13 +3582,9 @@ Before and after callbacks execute in the following order:
3558
3582
 
3559
3583
  Steps 4, 5 and 6 only happen if validation succeeds.
3560
3584
 
3561
- If a request for a resource is made with an unsupported HTTP method (returning
3562
- HTTP 405) only `before` callbacks will be executed. The remaining callbacks will
3563
- be bypassed.
3585
+ If a request for a resource is made with an unsupported HTTP method (returning HTTP 405) only `before` callbacks will be executed. The remaining callbacks will be bypassed.
3564
3586
 
3565
- If a request for a resource is made that triggers the built-in `OPTIONS` handler,
3566
- only `before` and `after` callbacks will be executed. The remaining callbacks will
3567
- be bypassed.
3587
+ If a request for a resource is made that triggers the built-in `OPTIONS` handler, only `before` and `after` callbacks will be executed. The remaining callbacks will be bypassed.
3568
3588
 
3569
3589
  For example, using a simple `before` block to set a header.
3570
3590
 
@@ -3709,11 +3729,7 @@ Instead of altering a response, you can also terminate and rewrite it from any c
3709
3729
 
3710
3730
  ## Anchoring
3711
3731
 
3712
- Grape by default anchors all request paths, which means that the request URL
3713
- should match from start to end to match, otherwise a `404 Not Found` is
3714
- returned. However, this is sometimes not what you want, because it is not always
3715
- known upfront what can be expected from the call. This is because Rack-mount by
3716
- default anchors requests to match from the start to the end, or not at all.
3732
+ Grape by default anchors all request paths, which means that the request URL should match from start to end to match, otherwise a `404 Not Found` is returned. However, this is sometimes not what you want, because it is not always known upfront what can be expected from the call. This is because Rack-mount by default anchors requests to match from the start to the end, or not at all.
3717
3733
  Rails solves this problem by using a `anchor: false` option in your routes.
3718
3734
  In Grape this option can be used as well when a method is defined.
3719
3735
 
@@ -3729,12 +3745,44 @@ class TwitterAPI < Grape::API
3729
3745
  end
3730
3746
  ```
3731
3747
 
3732
- This will match all paths starting with '/statuses/'. There is one caveat though:
3733
- the `params[:status]` parameter only holds the first part of the request url.
3734
- Luckily this can be circumvented by using the described above syntax for path
3735
- specification and using the `PATH_INFO` Rack environment variable, using
3736
- `env['PATH_INFO']`. This will hold everything that comes after the '/statuses/'
3737
- part.
3748
+ This will match all paths starting with '/statuses/'. There is one caveat though: the `params[:status]` parameter only holds the first part of the request url.
3749
+ Luckily this can be circumvented by using the described above syntax for path specification and using the `PATH_INFO` Rack environment variable, using `env['PATH_INFO']`. This will hold everything that comes after the '/statuses/' part.
3750
+
3751
+ ## Instance Variables
3752
+
3753
+ You can use instance variables to pass information across the various stages of a request. An instance variable set within a `before` validator is accessible within the endpoint's code and can also be utilized within the `rescue_from` handler.
3754
+
3755
+ ```ruby
3756
+ class TwitterAPI < Grape::API
3757
+ before do
3758
+ @var = 1
3759
+ end
3760
+
3761
+ get '/' do
3762
+ puts @var # => 1
3763
+ raise
3764
+ end
3765
+
3766
+ rescue_from :all do
3767
+ puts @var # => 1
3768
+ end
3769
+ end
3770
+ ```
3771
+
3772
+ The values of instance variables cannot be shared among various endpoints within the same API. This limitation arises due to Grape generating a new instance for each request made. Consequently, instance variables set within an endpoint during one request differ from those set during a subsequent request, as they exist within separate instances.
3773
+
3774
+ ```ruby
3775
+ class TwitterAPI < Grape::API
3776
+ get '/first' do
3777
+ @var = 1
3778
+ puts @var # => 1
3779
+ end
3780
+
3781
+ get '/second' do
3782
+ puts @var # => nil
3783
+ end
3784
+ end
3785
+ ```
3738
3786
 
3739
3787
  ## Using Custom Middleware
3740
3788
 
@@ -3943,8 +3991,7 @@ describe Twitter::API do
3943
3991
  end
3944
3992
  ```
3945
3993
 
3946
- In Rails, HTTP request tests would go into the `spec/requests` group. You may want your API code to go into
3947
- `app/api` - you can match that layout under `spec` by adding the following in `spec/rails_helper.rb`.
3994
+ In Rails, HTTP request tests would go into the `spec/requests` group. You may want your API code to go into `app/api` - you can match that layout under `spec` by adding the following in `spec/rails_helper.rb`.
3948
3995
 
3949
3996
  ```ruby
3950
3997
  RSpec.configure do |config|
@@ -3978,10 +4025,7 @@ end
3978
4025
 
3979
4026
  ### Stubbing Helpers
3980
4027
 
3981
- Because helpers are mixed in based on the context when an endpoint is defined, it can
3982
- be difficult to stub or mock them for testing. The `Grape::Endpoint.before_each` method
3983
- can help by allowing you to define behavior on the endpoint that will run before every
3984
- request.
4028
+ Because helpers are mixed in based on the context when an endpoint is defined, it can be difficult to stub or mock them for testing. The `Grape::Endpoint.before_each` method can help by allowing you to define behavior on the endpoint that will run before every request.
3985
4029
 
3986
4030
  ```ruby
3987
4031
  describe 'an endpoint that needs helpers stubbed' do
@@ -4107,8 +4151,7 @@ Grape integrates with following third-party tools:
4107
4151
 
4108
4152
  ## Contributing to Grape
4109
4153
 
4110
- Grape is work of hundreds of contributors. You're encouraged to submit pull requests, propose
4111
- features and discuss issues.
4154
+ Grape is work of hundreds of contributors. You're encouraged to submit pull requests, propose features and discuss issues.
4112
4155
 
4113
4156
  See [CONTRIBUTING](CONTRIBUTING.md).
4114
4157