grape 2.0.0 → 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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +404 -334
  5. data/UPGRADING.md +279 -7
  6. data/grape.gemspec +8 -8
  7. data/lib/grape/api/instance.rb +34 -66
  8. data/lib/grape/api.rb +47 -70
  9. data/lib/grape/content_types.rb +13 -10
  10. data/lib/grape/cookies.rb +31 -24
  11. data/lib/grape/dry_types.rb +0 -2
  12. data/lib/grape/dsl/api.rb +0 -2
  13. data/lib/grape/dsl/desc.rb +49 -44
  14. data/lib/grape/dsl/headers.rb +2 -2
  15. data/lib/grape/dsl/helpers.rb +8 -4
  16. data/lib/grape/dsl/inside_route.rb +67 -54
  17. data/lib/grape/dsl/parameters.rb +10 -9
  18. data/lib/grape/dsl/request_response.rb +14 -18
  19. data/lib/grape/dsl/routing.rb +34 -17
  20. data/lib/grape/dsl/validations.rb +13 -0
  21. data/lib/grape/endpoint.rb +120 -118
  22. data/lib/grape/{util/env.rb → env.rb} +0 -5
  23. data/lib/grape/error_formatter/base.rb +51 -21
  24. data/lib/grape/error_formatter/json.rb +7 -15
  25. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  26. data/lib/grape/error_formatter/txt.rb +11 -17
  27. data/lib/grape/error_formatter/xml.rb +3 -13
  28. data/lib/grape/error_formatter.rb +5 -25
  29. data/lib/grape/exceptions/base.rb +18 -30
  30. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  31. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  32. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  33. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  34. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  35. data/lib/grape/exceptions/validation.rb +5 -6
  36. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  37. data/lib/grape/exceptions/validation_errors.rb +4 -6
  38. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
  39. data/lib/grape/extensions/hash.rb +7 -2
  40. data/lib/grape/extensions/hashie/mash.rb +3 -5
  41. data/lib/grape/formatter/base.rb +16 -0
  42. data/lib/grape/formatter/json.rb +4 -6
  43. data/lib/grape/formatter/serializable_hash.rb +1 -1
  44. data/lib/grape/formatter/txt.rb +3 -5
  45. data/lib/grape/formatter/xml.rb +4 -6
  46. data/lib/grape/formatter.rb +7 -25
  47. data/lib/grape/{util/json.rb → json.rb} +1 -3
  48. data/lib/grape/locale/en.yml +46 -42
  49. data/lib/grape/middleware/auth/base.rb +11 -34
  50. data/lib/grape/middleware/auth/dsl.rb +23 -31
  51. data/lib/grape/middleware/base.rb +41 -23
  52. data/lib/grape/middleware/error.rb +77 -76
  53. data/lib/grape/middleware/formatter.rb +48 -79
  54. data/lib/grape/middleware/globals.rb +1 -3
  55. data/lib/grape/middleware/stack.rb +26 -37
  56. data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
  57. data/lib/grape/middleware/versioner/base.rb +74 -0
  58. data/lib/grape/middleware/versioner/header.rb +59 -126
  59. data/lib/grape/middleware/versioner/param.rb +4 -25
  60. data/lib/grape/middleware/versioner/path.rb +10 -34
  61. data/lib/grape/middleware/versioner.rb +7 -14
  62. data/lib/grape/namespace.rb +4 -5
  63. data/lib/grape/params_builder/base.rb +18 -0
  64. data/lib/grape/params_builder/hash.rb +11 -0
  65. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  66. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  67. data/lib/grape/params_builder.rb +32 -0
  68. data/lib/grape/parser/base.rb +16 -0
  69. data/lib/grape/parser/json.rb +6 -8
  70. data/lib/grape/parser/xml.rb +6 -8
  71. data/lib/grape/parser.rb +5 -23
  72. data/lib/grape/path.rb +38 -60
  73. data/lib/grape/request.rb +161 -30
  74. data/lib/grape/router/base_route.rb +39 -0
  75. data/lib/grape/router/greedy_route.rb +20 -0
  76. data/lib/grape/router/pattern.rb +45 -31
  77. data/lib/grape/router/route.rb +28 -57
  78. data/lib/grape/router.rb +56 -43
  79. data/lib/grape/util/base_inheritable.rb +4 -4
  80. data/lib/grape/util/cache.rb +0 -3
  81. data/lib/grape/util/endpoint_configuration.rb +1 -1
  82. data/lib/grape/util/header.rb +13 -0
  83. data/lib/grape/util/inheritable_values.rb +0 -2
  84. data/lib/grape/util/lazy/block.rb +29 -0
  85. data/lib/grape/util/lazy/value.rb +38 -0
  86. data/lib/grape/util/lazy/value_array.rb +21 -0
  87. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  88. data/lib/grape/util/lazy/value_hash.rb +21 -0
  89. data/lib/grape/util/media_type.rb +70 -0
  90. data/lib/grape/util/registry.rb +27 -0
  91. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  92. data/lib/grape/util/stackable_values.rb +1 -6
  93. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  94. data/lib/grape/validations/attributes_doc.rb +38 -36
  95. data/lib/grape/validations/attributes_iterator.rb +1 -0
  96. data/lib/grape/validations/contract_scope.rb +34 -0
  97. data/lib/grape/validations/params_scope.rb +36 -32
  98. data/lib/grape/validations/types/array_coercer.rb +0 -2
  99. data/lib/grape/validations/types/dry_type_coercer.rb +9 -15
  100. data/lib/grape/validations/types/json.rb +0 -2
  101. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  102. data/lib/grape/validations/types/set_coercer.rb +0 -3
  103. data/lib/grape/validations/types.rb +0 -3
  104. data/lib/grape/validations/validator_factory.rb +2 -2
  105. data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
  106. data/lib/grape/validations/validators/base.rb +8 -11
  107. data/lib/grape/validations/validators/coerce_validator.rb +1 -1
  108. data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
  109. data/lib/grape/validations/validators/default_validator.rb +6 -2
  110. data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
  111. data/lib/grape/validations/validators/except_values_validator.rb +2 -2
  112. data/lib/grape/validations/validators/length_validator.rb +49 -0
  113. data/lib/grape/validations/validators/presence_validator.rb +1 -1
  114. data/lib/grape/validations/validators/regexp_validator.rb +2 -2
  115. data/lib/grape/validations/validators/values_validator.rb +20 -57
  116. data/lib/grape/validations.rb +8 -21
  117. data/lib/grape/version.rb +1 -1
  118. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  119. data/lib/grape.rb +42 -274
  120. metadata +45 -44
  121. data/lib/grape/eager_load.rb +0 -20
  122. data/lib/grape/http/headers.rb +0 -71
  123. data/lib/grape/middleware/helpers.rb +0 -12
  124. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  125. data/lib/grape/router/attribute_translator.rb +0 -63
  126. data/lib/grape/util/lazy_block.rb +0 -27
  127. data/lib/grape/util/lazy_object.rb +0 -43
  128. data/lib/grape/util/lazy_value.rb +0 -91
  129. data/lib/grape/util/registrable.rb +0 -15
  130. data/lib/grape/validations/types/build_coercer.rb +0 -94
data/README.md CHANGED
@@ -1,11 +1,8 @@
1
1
  ![grape logo](grape.png)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/grape.svg)](http://badge.fury.io/rb/grape)
4
- [![Build Status](https://github.com/ruby-grape/grape/workflows/test/badge.svg?branch=master)](https://github.com/ruby-grape/grape/actions)
5
- [![Code Climate](https://codeclimate.com/github/ruby-grape/grape.svg)](https://codeclimate.com/github/ruby-grape/grape)
4
+ [![test](https://github.com/ruby-grape/grape/actions/workflows/test.yml/badge.svg)](https://github.com/ruby-grape/grape/actions/workflows/test.yml)
6
5
  [![Coverage Status](https://coveralls.io/repos/github/ruby-grape/grape/badge.svg?branch=master)](https://coveralls.io/github/ruby-grape/grape?branch=master)
7
- [![Inline docs](https://inch-ci.org/github/ruby-grape/grape.svg)](https://inch-ci.org/github/ruby-grape/grape)
8
- [![Join the chat at https://gitter.im/ruby-grape/grape](https://badges.gitter.im/ruby-grape/grape.svg)](https://gitter.im/ruby-grape/grape?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
9
6
 
10
7
  ## Table of Contents
11
8
 
@@ -19,21 +16,20 @@
19
16
  - [Mounting](#mounting)
20
17
  - [All](#all)
21
18
  - [Rack](#rack)
22
- - [ActiveRecord without Rails](#activerecord-without-rails)
23
- - [Rails 4](#rails-4)
24
- - [Rails 5+](#rails-5)
25
19
  - [Alongside Sinatra (or other frameworks)](#alongside-sinatra-or-other-frameworks)
26
20
  - [Rails](#rails)
27
- - [Rails < 5.2](#rails--52)
28
- - [Rails 6.0](#rails-60)
21
+ - [Zeitwerk](#zeitwerk)
29
22
  - [Modules](#modules)
30
23
  - [Remounting](#remounting)
31
24
  - [Mount Configuration](#mount-configuration)
32
25
  - [Versioning](#versioning)
33
- - [Path](#path)
34
- - [Header](#header)
35
- - [Accept-Version Header](#accept-version-header)
36
- - [Param](#param)
26
+ - [Strategies](#strategies)
27
+ - [Path](#path)
28
+ - [Header](#header)
29
+ - [Accept-Version Header](#accept-version-header)
30
+ - [Param](#param)
31
+ - [Linting](#linting)
32
+ - [Bug in Rack::ETag under Rack 3.X](#bug-in-racketag-under-rack-3x)
37
33
  - [Describing Methods](#describing-methods)
38
34
  - [Configuration](#configuration)
39
35
  - [Parameters](#parameters)
@@ -42,6 +38,7 @@
42
38
  - [Include Parent Namespaces](#include-parent-namespaces)
43
39
  - [Include Missing](#include-missing)
44
40
  - [Evaluate Given](#evaluate-given)
41
+ - [Parameter Precedence](#parameter-precedence)
45
42
  - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
46
43
  - [Supported Parameter Types](#supported-parameter-types)
47
44
  - [Integer/Fixnum and Coercions](#integerfixnum-and-coercions)
@@ -58,6 +55,7 @@
58
55
  - [values](#values)
59
56
  - [except_values](#except_values)
60
57
  - [same_as](#same_as)
58
+ - [length](#length)
61
59
  - [regexp](#regexp)
62
60
  - [mutually_exclusive](#mutually_exclusive)
63
61
  - [exactly_one_of](#exactly_one_of)
@@ -71,6 +69,7 @@
71
69
  - [Custom Validation messages](#custom-validation-messages)
72
70
  - [presence, allow_blank, values, regexp](#presence-allow_blank-values-regexp)
73
71
  - [same_as](#same_as-1)
72
+ - [length](#length-1)
74
73
  - [all_or_none_of](#all_or_none_of-1)
75
74
  - [mutually_exclusive](#mutually_exclusive-1)
76
75
  - [exactly_one_of](#exactly_one_of-1)
@@ -80,6 +79,7 @@
80
79
  - [Pass symbols for i18n translations](#pass-symbols-for-i18n-translations)
81
80
  - [Overriding Attribute Names](#overriding-attribute-names)
82
81
  - [With Default](#with-default)
82
+ - [Using dry-validation or dry-schema](#using-dry-validation-or-dry-schema)
83
83
  - [Headers](#headers)
84
84
  - [Request](#request)
85
85
  - [Header Case Handling](#header-case-handling)
@@ -100,7 +100,6 @@
100
100
  - [Rescuing exceptions inside namespaces](#rescuing-exceptions-inside-namespaces)
101
101
  - [Unrescuable Exceptions](#unrescuable-exceptions)
102
102
  - [Exceptions that should be rescued explicitly](#exceptions-that-should-be-rescued-explicitly)
103
- - [Rails 3.x](#rails-3x)
104
103
  - [Logging](#logging)
105
104
  - [API Formats](#api-formats)
106
105
  - [JSONP](#jsonp)
@@ -121,6 +120,7 @@
121
120
  - [Current Route and Endpoint](#current-route-and-endpoint)
122
121
  - [Before, After and Finally](#before-after-and-finally)
123
122
  - [Anchoring](#anchoring)
123
+ - [Instance Variables](#instance-variables)
124
124
  - [Using Custom Middleware](#using-custom-middleware)
125
125
  - [Grape Middleware](#grape-middleware)
126
126
  - [Rails Middleware](#rails-middleware)
@@ -152,23 +152,18 @@
152
152
 
153
153
  ## What is Grape?
154
154
 
155
- Grape is a REST-like API framework for Ruby. It's designed to run on Rack
156
- or complement existing web application frameworks such as Rails and Sinatra by
157
- providing a simple DSL to easily develop RESTful APIs. It has built-in support
158
- for common conventions, including multiple formats, subdomain/prefix restriction,
159
- content negotiation, versioning and much more.
155
+ 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.
160
156
 
161
157
  ## Stable Release
162
158
 
163
- You're reading the documentation for the stable release of Grape, **2.0.0**.
164
- Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
165
-
159
+ You're reading the documentation for the stable release of Grape, 2.4.0.
160
+ Please read [UPGRADING](https://github.com/ruby-grape/grape/blob/v2.4.0/UPGRADING.md) when upgrading from a previous version.
166
161
 
167
162
  ## Project Resources
168
163
 
169
164
  * [Grape Website](http://www.ruby-grape.org)
170
165
  * [Documentation](http://www.rubydoc.info/gems/grape)
171
- * Need help? Try [Grape Google Group](http://groups.google.com/group/ruby-grape) or [Gitter](https://gitter.im/ruby-grape/grape)
166
+ * Need help? [Open an Issue](https://github.com/ruby-grape/grape/issues)
172
167
  * [Follow us on Twitter](https://twitter.com/grapeframework)
173
168
 
174
169
  ## Grape for Enterprise
@@ -179,7 +174,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support
179
174
 
180
175
  ## Installation
181
176
 
182
- Ruby 2.6 or newer is required.
177
+ Ruby 2.7 or newer is required.
183
178
 
184
179
  Grape is available as a gem, to install it run:
185
180
 
@@ -188,8 +183,7 @@ Grape is available as a gem, to install it run:
188
183
  ## Basic Usage
189
184
 
190
185
  Grape APIs are Rack applications that are created by subclassing `Grape::API`.
191
- Below is a simple example showing some of the more common features of Grape in
192
- the context of recreating parts of the Twitter API.
186
+ Below is a simple example showing some of the more common features of Grape in the context of recreating parts of the Twitter API.
193
187
 
194
188
  ```ruby
195
189
  module Twitter
@@ -277,7 +271,7 @@ Grape's [deprecator](https://api.rubyonrails.org/v7.1.0/classes/ActiveSupport/De
277
271
  ### All
278
272
 
279
273
 
280
- By default Grape will compile the routes on the first route, it is possible to pre-load routes using the `compile!` method.
274
+ By default Grape will compile the routes on the first route, but it is possible to pre-load routes using the `compile!` method.
281
275
 
282
276
  ```ruby
283
277
  Twitter::API.compile!
@@ -287,8 +281,7 @@ This can be added to your `config.ru` (if using rackup), `application.rb` (if us
287
281
 
288
282
  ### Rack
289
283
 
290
- The above sample creates a Rack application that can be run from a rackup `config.ru` file
291
- with `rackup`:
284
+ The above sample creates a Rack application that can be run from a rackup `config.ru` file with `rackup`:
292
285
 
293
286
  ```ruby
294
287
  run Twitter::API
@@ -312,32 +305,9 @@ And would respond to the following routes:
312
305
 
313
306
  Grape will also automatically respond to HEAD and OPTIONS for all GET, and just OPTIONS for all other routes.
314
307
 
315
- ### ActiveRecord without Rails
316
-
317
- If you want to use ActiveRecord within Grape, you will need to make sure that ActiveRecord's connection pool
318
- is handled correctly.
319
-
320
- #### Rails 4
321
-
322
- The easiest way to achieve that is by using ActiveRecord's `ConnectionManagement` middleware in your
323
- `config.ru` before mounting Grape, e.g.:
324
-
325
- ```ruby
326
- use ActiveRecord::ConnectionAdapters::ConnectionManagement
327
- ```
328
-
329
- #### Rails 5+
330
-
331
- Use [otr-activerecord](https://github.com/jhollinger/otr-activerecord) as follows:
332
-
333
- ```ruby
334
- use OTR::ActiveRecord::ConnectionManagement
335
- ```
336
-
337
308
  ### Alongside Sinatra (or other frameworks)
338
309
 
339
- If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using
340
- `Rack::Cascade`:
310
+ If you wish to mount Grape alongside another Rack framework such as Sinatra, you can do so easily using `Rack::Cascade`:
341
311
 
342
312
  ```ruby
343
313
  # Example config.ru
@@ -373,21 +343,8 @@ Modify `config/routes`:
373
343
  ```ruby
374
344
  mount Twitter::API => '/'
375
345
  ```
376
-
377
- #### Rails < 5.2
378
-
379
- Modify `application.rb`:
380
-
381
- ```ruby
382
- config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
383
- config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
384
- ```
385
-
386
- See [below](#reloading-api-changes-in-development) for additional code that enables reloading of API changes in development.
387
-
388
- #### Rails 6.0
389
-
390
- 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:
346
+ #### Zeitwerk
347
+ 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:
391
348
 
392
349
  ```ruby
393
350
  ActiveSupport::Inflector.inflections(:en) do |inflect|
@@ -397,8 +354,7 @@ end
397
354
 
398
355
  ### Modules
399
356
 
400
- You can mount multiple API implementations inside another one. These don't have to be
401
- different versions, but may be components of the same API.
357
+ 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.
402
358
 
403
359
  ```ruby
404
360
  class Twitter::API < Grape::API
@@ -415,7 +371,7 @@ class Twitter::API < Grape::API
415
371
  end
416
372
  ```
417
373
 
418
- Keep in mind such declarations as `before/after/rescue_from` must be placed before `mount` in a case where they should be inherited.
374
+ Declarations as `before/after/rescue_from` can be placed before or after `mount`. In any case they will be inherited.
419
375
 
420
376
  ```ruby
421
377
  class Twitter::API < Grape::API
@@ -423,8 +379,20 @@ class Twitter::API < Grape::API
423
379
  header 'X-Base-Header', 'will be defined for all APIs that are mounted below'
424
380
  end
425
381
 
382
+ rescue_from :all do
383
+ error!({ "error" => "Internal Server Error" }, 500)
384
+ end
385
+
426
386
  mount Twitter::Users
427
387
  mount Twitter::Search
388
+
389
+ after do
390
+ clean_cache!
391
+ end
392
+
393
+ rescue_from ZeroDivisionError do
394
+ error!({ "error" => "Not found" }, 404)
395
+ end
428
396
  end
429
397
  ```
430
398
 
@@ -555,10 +523,69 @@ end
555
523
 
556
524
  ## Versioning
557
525
 
558
- There are four strategies in which clients can reach your API's endpoints: `:path`,
559
- `:header`, `:accept_version_header` and `:param`. The default strategy is `:path`.
526
+ 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.
527
+
528
+ ```ruby
529
+ require 'v1'
530
+ require 'v2'
531
+ require 'v3'
532
+ class App < Grape::API
533
+ mount V3
534
+ mount V2
535
+ mount V1
536
+ end
537
+ ```
538
+
539
+ To maintain the same endpoints from earlier API versions without rewriting them, you can indicate multiple versions within the previous API versions.
540
+
541
+ ```ruby
542
+ class V1 < Grape::API
543
+ version 'v1', 'v2', 'v3'
544
+
545
+ get '/foo' do
546
+ # your code for GET /foo
547
+ end
548
+
549
+ get '/other' do
550
+ # your code for GET /other
551
+ end
552
+ end
553
+
554
+ class V2 < Grape::API
555
+ version 'v2', 'v3'
556
+
557
+ get '/var' do
558
+ # your code for GET /var
559
+ end
560
+ end
561
+
562
+ class V3 < Grape::API
563
+ version 'v3'
564
+
565
+ get '/foo' do
566
+ # your new code for GET /foo
567
+ end
568
+ end
569
+ ```
570
+
571
+ Using the example provided, the subsequent endpoints will be accessible across various versions:
572
+
573
+ ```shell
574
+ GET /v1/foo
575
+ GET /v1/other
576
+ GET /v2/foo # => Same behavior as v1
577
+ GET /v2/other # => Same behavior as v1
578
+ GET /v2/var # => New endpoint not available in v1
579
+ GET /v3/foo # => Different behavior to v1 and v2
580
+ GET /v3/other # => Same behavior as v1 and v2
581
+ GET /v3/var # => Same behavior as v2
582
+ ```
583
+
584
+ 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`.
585
+
586
+ ### Strategies
560
587
 
561
- ### Path
588
+ #### Path
562
589
 
563
590
  ```ruby
564
591
  version 'v1', using: :path
@@ -568,7 +595,7 @@ Using this versioning strategy, clients should pass the desired version in the U
568
595
 
569
596
  curl http://localhost:9292/v1/statuses/public_timeline
570
597
 
571
- ### Header
598
+ #### Header
572
599
 
573
600
  ```ruby
574
601
  version 'v1', using: :header, vendor: 'twitter'
@@ -586,20 +613,15 @@ Using this versioning strategy, clients should pass the desired version in the H
586
613
 
587
614
  curl -H Accept:application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
588
615
 
589
- By default, the first matching version is used when no `Accept` header is
590
- supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
591
- one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
592
- is returned when no correct `Accept` header is supplied.
616
+ 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.
593
617
 
594
- When an invalid `Accept` header is supplied, a `406 Not Acceptable` error is returned if the `:cascade`
595
- option is set to `false`. Otherwise a `404 Not Found` error is returned by Rack if no other route
596
- matches.
618
+ 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.
597
619
 
598
620
  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:
599
621
 
600
622
  curl -H "Accept: text/xml;q=0.8, application/json;q=0.9" localhost:1234/resource
601
623
 
602
- ### Accept-Version Header
624
+ #### Accept-Version Header
603
625
 
604
626
  ```ruby
605
627
  version 'v1', using: :accept_version_header
@@ -609,20 +631,15 @@ Using this versioning strategy, clients should pass the desired version in the H
609
631
 
610
632
  curl -H "Accept-Version:v1" http://localhost:9292/statuses/public_timeline
611
633
 
612
- By default, the first matching version is used when no `Accept-Version` header is
613
- supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
614
- one could use the `:strict` option. When this option is set to `true`, a `406 Not Acceptable` error
615
- is returned when no correct `Accept` header is supplied and the `:cascade` option is set to `false`.
616
- Otherwise a `404 Not Found` error is returned by Rack if no other route matches.
634
+ 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.
617
635
 
618
- ### Param
636
+ #### Param
619
637
 
620
638
  ```ruby
621
639
  version 'v1', using: :param
622
640
  ```
623
641
 
624
- Using this versioning strategy, clients should pass the desired version as a request parameter,
625
- either in the URL query string or in the request body.
642
+ 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.
626
643
 
627
644
  curl http://localhost:9292/statuses/public_timeline?apiver=v1
628
645
 
@@ -635,6 +652,27 @@ version 'v1', using: :param, parameter: 'v'
635
652
  curl http://localhost:9292/statuses/public_timeline?v=v1
636
653
 
637
654
 
655
+ ## Linting
656
+
657
+ You can check whether your API is in conformance with the [Rack's specification](https://github.com/rack/rack/blob/main/SPEC.rdoc) by calling `lint!` at the API level or through [configuration](#configuration).
658
+
659
+ ```ruby
660
+ class Api < Grape::API
661
+ lint!
662
+ end
663
+ ```
664
+ ```ruby
665
+ Grape.configure do |config|
666
+ config.lint = true
667
+ end
668
+ ```
669
+ ```ruby
670
+ Grape.config.lint = true
671
+ ```
672
+
673
+ ### Bug in Rack::ETag under Rack 3.X
674
+ If you're using Rack 3.X and the `Rack::Etag` middleware (used by [Rails](https://guides.rubyonrails.org/rails_on_rack.html#inspecting-middleware-stack)), a [bug](https://github.com/rack/rack/pull/2324) related to linting has been fixed in [3.1.13](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3113---2025-04-13) and [3.0.15](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3015---2025-04-13) respectively.
675
+
638
676
  ## Describing Methods
639
677
 
640
678
  You can add a description to API methods and namespaces. The description would be used by [grape-swagger][grape-swagger] to generate swagger compliant documentation.
@@ -701,10 +739,13 @@ For example, for the `param_builder`, the following code could run in an initial
701
739
 
702
740
  ```ruby
703
741
  Grape.configure do |config|
704
- config.param_builder = Grape::Extensions::Hashie::Mash::ParamBuilder
742
+ config.param_builder = :hashie_mash
705
743
  end
706
744
  ```
707
745
 
746
+ Available parameter builders are `:hash`, `:hash_with_indifferent_access`, and `:hashie_mash`.
747
+ See [params_builder](lib/grape/params_builder).
748
+
708
749
  You can also configure a single API:
709
750
 
710
751
  ```ruby
@@ -713,13 +754,11 @@ API.configure do |config|
713
754
  end
714
755
  ```
715
756
 
716
- This will be available inside the API with `configuration`, as if it were
717
- [mount configuration](#mount-configuration).
757
+ This will be available inside the API with `configuration`, as if it were [mount configuration](#mount-configuration).
718
758
 
719
759
  ## Parameters
720
760
 
721
- Request parameters are available through the `params` hash object. This includes `GET`, `POST`
722
- and `PUT` parameters, along with any named parameters you specify in your route strings.
761
+ 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.
723
762
 
724
763
  ```ruby
725
764
  get :public_timeline do
@@ -727,8 +766,7 @@ get :public_timeline do
727
766
  end
728
767
  ```
729
768
 
730
- Parameters are automatically populated from the request body on `POST` and `PUT` for form input, JSON and
731
- XML content-types.
769
+ Parameters are automatically populated from the request body on `POST` and `PUT` for form input, JSON and XML content-types.
732
770
 
733
771
  The request:
734
772
 
@@ -774,7 +812,7 @@ By default parameters are available as `ActiveSupport::HashWithIndifferentAccess
774
812
 
775
813
  ```ruby
776
814
  class API < Grape::API
777
- include Grape::Extensions::Hashie::Mash::ParamBuilder
815
+ build_with :hashie_mash
778
816
 
779
817
  params do
780
818
  optional :color, type: String
@@ -788,16 +826,15 @@ The class can also be overridden on individual parameter blocks using `build_wit
788
826
 
789
827
  ```ruby
790
828
  params do
791
- build_with Grape::Extensions::Hash::ParamBuilder
829
+ build_with :hash
792
830
  optional :color, type: String
793
831
  end
794
832
  ```
795
833
 
796
- Or globally with the [Configuration](#configuration) `Grape.configure.param_builder`.
797
-
798
834
  In the example above, `params["color"]` will return `nil` since `params` is a plain `Hash`.
799
835
 
800
- Available parameter builders are `Grape::Extensions::Hash::ParamBuilder`, `Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder` and `Grape::Extensions::Hashie::Mash::ParamBuilder`.
836
+ Available parameter builders are `:hash`, `:hash_with_indifferent_access`, and `:hashie_mash`.
837
+ See [params_builder](lib/grape/params_builder).
801
838
 
802
839
  ### Declared
803
840
 
@@ -1067,8 +1104,7 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
1067
1104
  }
1068
1105
  ````
1069
1106
 
1070
- Note that an attribute with a `nil` value is not considered *missing* and will also be returned
1071
- when `include_missing` is set to `false`:
1107
+ Note that an attribute with a `nil` value is not considered *missing* and will also be returned when `include_missing` is set to `false`:
1072
1108
 
1073
1109
  **Request**
1074
1110
 
@@ -1186,6 +1222,35 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/child -d '{"chil
1186
1222
  }
1187
1223
  ````
1188
1224
 
1225
+ ### Parameter Precedence
1226
+
1227
+ Using `route_param` takes higher precedence over a regular parameter defined with same name:
1228
+
1229
+ ```ruby
1230
+ params do
1231
+ requires :foo, type: String
1232
+ end
1233
+ route_param :foo do
1234
+ get do
1235
+ { value: params[:foo] }
1236
+ end
1237
+ end
1238
+ ```
1239
+
1240
+ **Request**
1241
+
1242
+ ```bash
1243
+ curl -X POST -H "Content-Type: application/json" localhost:9292/bar -d '{"foo": "baz"}'
1244
+ ```
1245
+
1246
+ **Response**
1247
+
1248
+ ```json
1249
+ {
1250
+ "value": "bar"
1251
+ }
1252
+ ```
1253
+
1189
1254
  ## Parameter Validation and Coercion
1190
1255
 
1191
1256
  You can define validations and coercion options for your parameters using a `params` block.
@@ -1207,8 +1272,7 @@ put ':id' do
1207
1272
  end
1208
1273
  ```
1209
1274
 
1210
- When a type is specified an implicit validation is done after the coercion to ensure
1211
- the output type is the one declared.
1275
+ When a type is specified an implicit validation is done after the coercion to ensure the output type is the one declared.
1212
1276
 
1213
1277
  Optional parameters can have a default value.
1214
1278
 
@@ -1220,9 +1284,7 @@ params do
1220
1284
  end
1221
1285
  ```
1222
1286
 
1223
- Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same
1224
- number for each call to the endpoint of this `params` block. To have the default evaluate
1225
- lazily with each request use a lambda, like `:random_number` above.
1287
+ 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.
1226
1288
 
1227
1289
  Note that default values will be passed through to any validation options specified.
1228
1290
  The following example will always fail if `:color` is not explicitly provided.
@@ -1241,6 +1303,15 @@ params do
1241
1303
  end
1242
1304
  ```
1243
1305
 
1306
+ 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.
1307
+
1308
+ ```ruby
1309
+ params do
1310
+ optional :color, type: String, default: 'blue'
1311
+ optional :primary_color, type: String, default: -> (params) { params[:color] }
1312
+ end
1313
+ ```
1314
+
1244
1315
  ### Supported Parameter Types
1245
1316
 
1246
1317
  The following are all valid types, supported out of the box by Grape:
@@ -1282,12 +1353,7 @@ get '/int' integers: { int: '45' }
1282
1353
 
1283
1354
  ### Custom Types and Coercions
1284
1355
 
1285
- Aside from the default set of supported types listed above, any class can be
1286
- used as a type as long as an explicit coercion method is supplied. If the type
1287
- implements a class-level `parse` method, Grape will use it automatically.
1288
- This method must take one string argument and return an instance of the correct
1289
- type, or return an instance of `Grape::Types::InvalidValue` which optionally
1290
- accepts a message to be returned in the response.
1356
+ 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.
1291
1357
 
1292
1358
  ```ruby
1293
1359
  class Color
@@ -1297,7 +1363,7 @@ class Color
1297
1363
  end
1298
1364
 
1299
1365
  def self.parse(value)
1300
- return new(value) if %w[blue red green]).include?(value)
1366
+ return new(value) if %w[blue red green].include?(value)
1301
1367
 
1302
1368
  Grape::Types::InvalidValue.new('Unsupported color')
1303
1369
  end
@@ -1315,10 +1381,7 @@ get '/stuff' do
1315
1381
  end
1316
1382
  ```
1317
1383
 
1318
- Alternatively, a custom coercion method may be supplied for any type of parameter
1319
- using `coerce_with`. Any class or object may be given that implements a `parse` or
1320
- `call` method, in that order of precedence. The method must accept a single string
1321
- parameter, and the return value must match the given `type`.
1384
+ 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`.
1322
1385
 
1323
1386
  ```ruby
1324
1387
  params do
@@ -1342,9 +1405,7 @@ params do
1342
1405
  end
1343
1406
  ```
1344
1407
 
1345
- Grape will assert that coerced values match the given `type`, and will reject the request
1346
- if they do not. To override this behaviour, custom types may implement a `parsed?` method
1347
- that should accept a single argument and return `true` if the value passes type validation.
1408
+ 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.
1348
1409
 
1349
1410
  ```ruby
1350
1411
  class SecureUri
@@ -1379,9 +1440,7 @@ end
1379
1440
 
1380
1441
  ### First-Class `JSON` Types
1381
1442
 
1382
- Grape supports complex parameters given as JSON-formatted strings using the special `type: JSON`
1383
- declaration. JSON objects and arrays of objects are accepted equally, with nested validation
1384
- rules applied to all objects in either case:
1443
+ 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:
1385
1444
 
1386
1445
  ```ruby
1387
1446
  params do
@@ -1400,8 +1459,7 @@ client.get('/', json: '{"int":4}') # => HTTP 400
1400
1459
  client.get('/', json: '[{"int":4}]') # => HTTP 400
1401
1460
  ```
1402
1461
 
1403
- Additionally `type: Array[JSON]` may be used, which explicitly marks the parameter as an array
1404
- of objects. If a single object is supplied it will be wrapped.
1462
+ 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.
1405
1463
 
1406
1464
  ```ruby
1407
1465
  params do
@@ -1413,8 +1471,7 @@ get '/' do
1413
1471
  params[:json].each { |obj| ... } # always works
1414
1472
  end
1415
1473
  ```
1416
- For stricter control over the type of JSON structure which may be supplied,
1417
- use `type: Array, coerce_with: JSON` or `type: Hash, coerce_with: JSON`.
1474
+ 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`.
1418
1475
 
1419
1476
  ### Multiple Allowed Types
1420
1477
 
@@ -1433,8 +1490,7 @@ client.get('/', status_code: 300) # => 300
1433
1490
  client.get('/', status_code: %w(404 NOT FOUND)) # => [404, "NOT", "FOUND"]
1434
1491
  ```
1435
1492
 
1436
- As a special case, variant-member-type collections may also be declared, by
1437
- passing a `Set` or `Array` with more than one member to `type`:
1493
+ 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`:
1438
1494
 
1439
1495
  ```ruby
1440
1496
  params do
@@ -1450,11 +1506,8 @@ client.get('/', status_codes: %w(1 two)) # => [1, "two"]
1450
1506
  ### Validation of Nested Parameters
1451
1507
 
1452
1508
  Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
1453
- In the [above example](#parameter-validation-and-coercion), this means `params[:media][:url]` is required along with `params[:id]`,
1454
- and `params[:audio][:format]` is required only if `params[:audio]` is present.
1455
- With a block, `group`, `requires` and `optional` accept an additional option `type` which can
1456
- be either `Array` or `Hash`, and defaults to `Array`. Depending on the value, the nested
1457
- parameters will be treated either as values of a hash or as values of hashes in an array.
1509
+ 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.
1510
+ 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.
1458
1511
 
1459
1512
  ```ruby
1460
1513
  params do
@@ -1472,9 +1525,7 @@ end
1472
1525
 
1473
1526
  ### Dependent Parameters
1474
1527
 
1475
- Suppose some of your parameters are only relevant if another parameter is given;
1476
- Grape allows you to express this relationship through the `given` method in your
1477
- parameters block, like so:
1528
+ 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:
1478
1529
 
1479
1530
  ```ruby
1480
1531
  params do
@@ -1513,31 +1564,45 @@ Note: param in `given` should be the renamed one. In the example, it should be `
1513
1564
 
1514
1565
  ### Group Options
1515
1566
 
1516
- Parameters options can be grouped. It can be useful if you want to extract
1517
- common validation or types for several parameters. The example below presents a
1518
- typical case when parameters share common options.
1567
+ Parameters options can be grouped. It can be useful if you want to extract common validation or types for several parameters.
1568
+ 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.
1569
+
1570
+ The example below presents a typical case when parameters share common options.
1519
1571
 
1520
1572
  ```ruby
1521
1573
  params do
1522
- requires :first_name, type: String, regexp: /w+/, desc: 'First name'
1523
- requires :middle_name, type: String, regexp: /w+/, desc: 'Middle name'
1524
- requires :last_name, type: String, regexp: /w+/, desc: 'Last name'
1574
+ requires :first_name, type: String, regexp: /w+/, desc: 'First name', documentation: { in: 'body' }
1575
+ optional :middle_name, type: String, regexp: /w+/, desc: 'Middle name', documentation: { in: 'body', x: { nullable: true } }
1576
+ requires :last_name, type: String, regexp: /w+/, desc: 'Last name', documentation: { in: 'body' }
1525
1577
  end
1526
1578
  ```
1527
1579
 
1528
- Grape allows you to present the same logic through the `with` method in your
1529
- parameters block, like so:
1580
+ Grape allows you to present the same logic through the `with` method in your parameters block, like so:
1530
1581
 
1531
1582
  ```ruby
1532
1583
  params do
1533
- with(type: String, regexp: /w+/) do
1584
+ with(type: String, regexp: /w+/, documentation: { in: 'body' }) do
1534
1585
  requires :first_name, desc: 'First name'
1535
- requires :middle_name, desc: 'Middle name'
1586
+ optional :middle_name, desc: 'Middle name', documentation: { x: { nullable: true } }
1536
1587
  requires :last_name, desc: 'Last name'
1537
1588
  end
1538
1589
  end
1539
1590
  ```
1540
1591
 
1592
+ 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.
1593
+
1594
+ ```ruby
1595
+ params do
1596
+ with(documentation: { in: 'body' }) do # Applies documentation to all nested parameters
1597
+ with(type: String, regexp: /\w+/) do # Applies type and validation to names
1598
+ requires :first_name, desc: 'First name'
1599
+ requires :last_name, desc: 'Last name'
1600
+ end
1601
+ optional :age, type: Integer, desc: 'Age', documentation: { x: { nullable: true } } # Specific settings for 'age'
1602
+ end
1603
+ end
1604
+ ```
1605
+
1541
1606
  ### Renaming
1542
1607
 
1543
1608
  You can rename parameters using `as`, which can be useful when refactoring existing APIs:
@@ -1560,13 +1625,9 @@ The value passed to `as` will be the key when calling `declared(params)`.
1560
1625
 
1561
1626
  #### `allow_blank`
1562
1627
 
1563
- Parameters can be defined as `allow_blank`, ensuring that they contain a value. By default, `requires`
1564
- only validates that a parameter was sent in the request, regardless its value. With `allow_blank: false`,
1565
- empty values or whitespace only values are invalid.
1628
+ 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.
1566
1629
 
1567
- `allow_blank` can be combined with both `requires` and `optional`. If the parameter is required, it has to contain
1568
- 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
1569
- some value, and not an empty string/only whitespaces.
1630
+ `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.
1570
1631
 
1571
1632
 
1572
1633
  ```ruby
@@ -1617,11 +1678,9 @@ end
1617
1678
  ```
1618
1679
 
1619
1680
  The `:values` option can also be supplied with a `Proc`, evaluated lazily with each request.
1620
- If the Proc has arity zero (i.e. it takes no arguments) it is expected to return either a list
1621
- or a range which will then be used to validate the parameter.
1681
+ 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.
1622
1682
 
1623
- For example, given a status model you may want to restrict by hashtags that you have
1624
- previously defined in the `HashTag` model.
1683
+ For example, given a status model you may want to restrict by hashtags that you have previously defined in the `HashTag` model.
1625
1684
 
1626
1685
  ```ruby
1627
1686
  params do
@@ -1629,10 +1688,7 @@ params do
1629
1688
  end
1630
1689
  ```
1631
1690
 
1632
- Alternatively, a Proc with arity one (i.e. taking one argument) can be used to explicitly validate
1633
- each parameter value. In that case, the Proc is expected to return a truthy value if the parameter
1634
- value is valid. The parameter will be considered invalid if the Proc returns a falsy value or if it
1635
- raises a StandardError.
1691
+ 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.
1636
1692
 
1637
1693
  ```ruby
1638
1694
  params do
@@ -1654,9 +1710,7 @@ end
1654
1710
 
1655
1711
  Parameters can be restricted from having a specific set of values with the `:except_values` option.
1656
1712
 
1657
- The `except_values` validator behaves similarly to the `values` validator in that it accepts either
1658
- an Array, a Range, or a Proc. Unlike the `values` validator, however, `except_values` only accepts
1659
- Procs with arity zero.
1713
+ 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.
1660
1714
 
1661
1715
  ```ruby
1662
1716
  params do
@@ -1677,11 +1731,24 @@ params do
1677
1731
  end
1678
1732
  ```
1679
1733
 
1734
+ #### `length`
1735
+
1736
+ Parameters with types that support `#length` method can be restricted to have a specific length with the `:length` option.
1737
+
1738
+ The validator accepts `:min` or `:max` or both options or only `:is` to validate that the value of the parameter is within the given limits.
1739
+
1740
+ ```ruby
1741
+ params do
1742
+ requires :code, type: String, length: { is: 2 }
1743
+ requires :str, type: String, length: { min: 3 }
1744
+ requires :list, type: [Integer], length: { min: 3, max: 5 }
1745
+ requires :hash, type: Hash, length: { max: 5 }
1746
+ end
1747
+ ```
1748
+
1680
1749
  #### `regexp`
1681
1750
 
1682
- Parameters can be restricted to match a specific regular expression with the `:regexp` option. If the value
1683
- does not match the regular expression an error will be returned. Note that this is true for both `requires`
1684
- and `optional` parameters.
1751
+ 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.
1685
1752
 
1686
1753
  ```ruby
1687
1754
  params do
@@ -1816,8 +1883,7 @@ namespace :statuses do
1816
1883
  end
1817
1884
  ```
1818
1885
 
1819
- The `namespace` method has a number of aliases, including: `group`, `resource`,
1820
- `resources`, and `segment`. Use whichever reads the best for your API.
1886
+ The `namespace` method has a number of aliases, including: `group`, `resource`, `resources`, and `segment`. Use whichever reads the best for your API.
1821
1887
 
1822
1888
  You can conveniently define a route parameter as a namespace using `route_param`.
1823
1889
 
@@ -1972,8 +2038,7 @@ end
1972
2038
 
1973
2039
  ### I18n
1974
2040
 
1975
- Grape supports I18n for parameter-related error messages, but will fallback to English if
1976
- translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
2041
+ 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.
1977
2042
 
1978
2043
  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.
1979
2044
 
@@ -1998,6 +2063,16 @@ params do
1998
2063
  end
1999
2064
  ```
2000
2065
 
2066
+ #### `length`
2067
+
2068
+ ```ruby
2069
+ params do
2070
+ requires :code, type: String, length: { is: 2, message: 'code is expected to be exactly 2 characters long' }
2071
+ requires :str, type: String, length: { min: 5, message: 'str is expected to be at least 5 characters long' }
2072
+ requires :list, type: [Integer], length: { min: 2, max: 3, message: 'list is expected to have between 2 and 3 elements' }
2073
+ end
2074
+ ```
2075
+
2001
2076
  #### `all_or_none_of`
2002
2077
 
2003
2078
  ```ruby
@@ -2106,6 +2181,40 @@ params do
2106
2181
  end
2107
2182
  ```
2108
2183
 
2184
+ ### Using `dry-validation` or `dry-schema`
2185
+
2186
+ 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`.
2187
+
2188
+ Then call `contract` with a contract or schema defined previously:
2189
+
2190
+ ```rb
2191
+ CreateOrdersSchema = Dry::Schema.Params do
2192
+ required(:orders).array(:hash) do
2193
+ required(:name).filled(:string)
2194
+ optional(:volume).maybe(:integer, lt?: 9)
2195
+ end
2196
+ end
2197
+
2198
+ # ...
2199
+
2200
+ contract CreateOrdersSchema
2201
+ ```
2202
+
2203
+ or with a block, using the [schema definition syntax](https://dry-rb.org/gems/dry-schema/1.13/#quick-start):
2204
+
2205
+ ```rb
2206
+ contract do
2207
+ required(:orders).array(:hash) do
2208
+ required(:name).filled(:string)
2209
+ optional(:volume).maybe(:integer, lt?: 9)
2210
+ end
2211
+ end
2212
+ ```
2213
+
2214
+ 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.
2215
+
2216
+ 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.
2217
+
2109
2218
  ## Headers
2110
2219
 
2111
2220
  ### Request
@@ -2205,8 +2314,7 @@ namespace ':id' do
2205
2314
  end
2206
2315
  ```
2207
2316
 
2208
- Optionally, you can define requirements for your named route parameters using regular
2209
- expressions on namespace or endpoint. The route will match only if all requirements are met.
2317
+ 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.
2210
2318
 
2211
2319
  ```ruby
2212
2320
  get ':id', requirements: { id: /[0-9]*/ } do
@@ -2224,8 +2332,7 @@ end
2224
2332
 
2225
2333
  ## Helpers
2226
2334
 
2227
- You can define helper methods that your endpoints can use with the `helpers`
2228
- macro by either giving a block or an array of modules.
2335
+ You can define helper methods that your endpoints can use with the `helpers` macro by either giving a block or an array of modules.
2229
2336
 
2230
2337
  ```ruby
2231
2338
  module StatusHelpers
@@ -2464,11 +2571,36 @@ end
2464
2571
  API.recognize_path '/statuses'
2465
2572
  ```
2466
2573
 
2574
+ Since version `2.1.0`, the `recognize_path` method takes into account the parameters type to determine which endpoint should match with given path.
2575
+
2576
+ ```ruby
2577
+ class Books < Grape::API
2578
+ resource :books do
2579
+ route_param :id, type: Integer do
2580
+ # GET /books/:id
2581
+ get do
2582
+ #...
2583
+ end
2584
+ end
2585
+
2586
+ resource :share do
2587
+ # POST /books/share
2588
+ post do
2589
+ # ....
2590
+ end
2591
+ end
2592
+ end
2593
+ end
2594
+
2595
+ API.recognize_path '/books/1' # => /books/:id
2596
+ API.recognize_path '/books/share' # => /books/share
2597
+ API.recognize_path '/books/other' # => nil
2598
+ ```
2599
+
2600
+
2467
2601
  ## Allowed Methods
2468
2602
 
2469
- When you add a `GET` route for a resource, a route for the `HEAD`
2470
- method will also be added automatically. You can disable this
2471
- behavior with `do_not_route_head!`.
2603
+ 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!`.
2472
2604
 
2473
2605
  ``` ruby
2474
2606
  class API < Grape::API
@@ -2480,11 +2612,7 @@ class API < Grape::API
2480
2612
  end
2481
2613
  ```
2482
2614
 
2483
- When you add a route for a resource, a route for the `OPTIONS`
2484
- method will also be added. The response to an OPTIONS request will
2485
- include an "Allow" header listing the supported methods. If the resource
2486
- has `before` and `after` callbacks they will be executed, but no other callbacks will
2487
- run.
2615
+ 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.
2488
2616
 
2489
2617
  ```ruby
2490
2618
  class API < Grape::API
@@ -2513,10 +2641,7 @@ curl -v -X OPTIONS http://localhost:3000/rt_count
2513
2641
 
2514
2642
  You can disable this behavior with `do_not_route_options!`.
2515
2643
 
2516
- If a request for a resource is made with an unsupported HTTP method, an
2517
- HTTP 405 (Method Not Allowed) response will be returned. If the resource
2518
- has `before` callbacks they will be executed, but no other callbacks will
2519
- run.
2644
+ 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.
2520
2645
 
2521
2646
  ``` shell
2522
2647
  curl -X DELETE -v http://localhost:3000/rt_count/
@@ -2542,8 +2667,7 @@ Anything that responds to `#to_s` can be given as a first argument to `error!`.
2542
2667
  error! :not_found, 404
2543
2668
  ```
2544
2669
 
2545
- You can also return JSON formatted objects by raising error! and passing a hash
2546
- instead of a message.
2670
+ You can also return JSON formatted objects by raising error! and passing a hash instead of a message.
2547
2671
 
2548
2672
  ```ruby
2549
2673
  error!({ error: 'unexpected error', detail: 'missing widget' }, 500)
@@ -2608,8 +2732,7 @@ route :any, '*path' do
2608
2732
  end
2609
2733
  ```
2610
2734
 
2611
- It is very crucial to __define this endpoint at the very end of your API__, as it
2612
- literally accepts every request.
2735
+ It is very crucial to __define this endpoint at the very end of your API__, as it literally accepts every request.
2613
2736
 
2614
2737
  ## Exception Handling
2615
2738
 
@@ -2851,33 +2974,11 @@ Any exception that is not subclass of `StandardError` should be rescued explicit
2851
2974
  Usually it is not a case for an application logic as such errors point to problems in Ruby runtime.
2852
2975
  This is following [standard recommendations for exceptions handling](https://ruby-doc.org/core/Exception.html).
2853
2976
 
2854
- ### Rails 3.x
2855
-
2856
- When mounted inside containers, such as Rails 3.x, errors such as "404 Not Found" or
2857
- "406 Not Acceptable" will likely be handled and rendered by Rails handlers. For instance,
2858
- accessing a nonexistent route "/api/foo" raises a 404, which inside rails will ultimately
2859
- be translated to an `ActionController::RoutingError`, which most likely will get rendered
2860
- to a HTML error page.
2861
-
2862
- Most APIs will enjoy preventing downstream handlers from handling errors. You may set the
2863
- `:cascade` option to `false` for the entire API or separately on specific `version` definitions,
2864
- which will remove the `X-Cascade: true` header from API responses.
2865
-
2866
- ```ruby
2867
- cascade false
2868
- ```
2869
-
2870
- ```ruby
2871
- version 'v1', using: :header, vendor: 'twitter', cascade: false
2872
- ```
2873
-
2874
2977
  ## Logging
2875
2978
 
2876
- `Grape::API` provides a `logger` method which by default will return an instance of the `Logger`
2877
- class from Ruby's standard library.
2979
+ `Grape::API` provides a `logger` method which by default will return an instance of the `Logger` class from Ruby's standard library.
2878
2980
 
2879
- To log messages from within an endpoint, you need to define a helper to make the logger
2880
- available in the endpoint context.
2981
+ To log messages from within an endpoint, you need to define a helper to make the logger available in the endpoint context.
2881
2982
 
2882
2983
  ```ruby
2883
2984
  class API < Grape::API
@@ -2926,9 +3027,7 @@ For similar to Rails request logging try the [grape_logging](https://github.com/
2926
3027
 
2927
3028
  ## API Formats
2928
3029
 
2929
- Your API can declare which content-types to support by using `content_type`. If you do not specify any, Grape will support
2930
- _XML_, _JSON_, _BINARY_, and _TXT_ content-types. The default format is `:txt`; you can change this with `default_format`.
2931
- Essentially, the two APIs below are equivalent.
3030
+ 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.
2932
3031
 
2933
3032
  ```ruby
2934
3033
  class Twitter::API < Grape::API
@@ -2947,9 +3046,7 @@ class Twitter::API < Grape::API
2947
3046
  end
2948
3047
  ```
2949
3048
 
2950
- If you declare any `content_type` whatsoever, the Grape defaults will be overridden. For example, the following API will only
2951
- support the `:xml` and `:rss` content-types, but not `:txt`, `:json`, or `:binary`. Importantly, this means the `:txt`
2952
- default format is not supported! So, make sure to set a new `default_format`.
3049
+ 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`.
2953
3050
 
2954
3051
  ```ruby
2955
3052
  class Twitter::API < Grape::API
@@ -2960,8 +3057,7 @@ class Twitter::API < Grape::API
2960
3057
  end
2961
3058
  ```
2962
3059
 
2963
- Serialization takes place automatically. For example, you do not have to call `to_json` in each JSON API endpoint
2964
- implementation. The response format (and thus the automatic serialization) is determined in the following order:
3060
+ 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:
2965
3061
  * Use the file extension, if specified. If the file is .json, choose the JSON format.
2966
3062
  * Use the value of the `format` parameter in the query string, if specified.
2967
3063
  * Use the format set by the `format` option, if specified.
@@ -2984,20 +3080,15 @@ class MultipleFormatAPI < Grape::API
2984
3080
  end
2985
3081
  ```
2986
3082
 
2987
- * `GET /hello` (with an `Accept: */*` header) does not have an extension or a `format` parameter, so it will respond with
2988
- JSON (the default format).
3083
+ * `GET /hello` (with an `Accept: */*` header) does not have an extension or a `format` parameter, so it will respond with JSON (the default format).
2989
3084
  * `GET /hello.xml` has a recognized extension, so it will respond with XML.
2990
3085
  * `GET /hello?format=xml` has a recognized `format` parameter, so it will respond with XML.
2991
- * `GET /hello.xml?format=json` has a recognized extension (which takes precedence over the `format` parameter), so it will
2992
- respond with XML.
2993
- * `GET /hello.xls` (with an `Accept: */*` header) has an extension, but that extension is not recognized, so it will respond
2994
- with JSON (the default format).
2995
- * `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header
2996
- corresponds to a recognized format, so it will respond with XML.
2997
- * `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header,
2998
- so it will respond with JSON (the default format).
2999
-
3000
- You can override this process explicitly by specifying `env['api.format']` in the API itself.
3086
+ * `GET /hello.xml?format=json` has a recognized extension (which takes precedence over the `format` parameter), so it will respond with XML.
3087
+ * `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).
3088
+ * `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.
3089
+ * `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).
3090
+
3091
+ You can override this process explicitly by calling `api_format` in the API itself.
3001
3092
  For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
3002
3093
 
3003
3094
  ```ruby
@@ -3005,15 +3096,14 @@ class Twitter::API < Grape::API
3005
3096
  post 'attachment' do
3006
3097
  filename = params[:file][:filename]
3007
3098
  content_type MIME::Types.type_for(filename)[0].to_s
3008
- env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
3099
+ api_format :binary # there's no formatter for :binary, data will be returned "as is"
3009
3100
  header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(filename)}"
3010
3101
  params[:file][:tempfile].read
3011
3102
  end
3012
3103
  end
3013
3104
  ```
3014
3105
 
3015
- You can have your API only respond to a single format with `format`. If you use this, the API will **not** respond to file
3016
- extensions other than specified in `format`. For example, consider the following API.
3106
+ 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.
3017
3107
 
3018
3108
  ```ruby
3019
3109
  class SingleFormatAPI < Grape::API
@@ -3028,14 +3118,10 @@ end
3028
3118
  * `GET /hello` will respond with JSON.
3029
3119
  * `GET /hello.json` will respond with JSON.
3030
3120
  * `GET /hello.xml`, `GET /hello.foobar`, or *any* other extension will respond with an HTTP 404 error code.
3031
- * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter
3032
- is not supported.
3033
- * `GET /hello` with an `Accept: application/xml` header will still respond with JSON, since it could not negotiate a
3034
- recognized content-type from the headers and JSON is the effective default.
3121
+ * `GET /hello?format=xml` will respond with an HTTP 406 error code, because the XML format specified by the request parameter is not supported.
3122
+ * `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.
3035
3123
 
3036
- The formats apply to parsing, too. The following API will only respond to the JSON content-type and will not parse any other
3037
- input than `application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`, `multipart/related` and
3038
- `multipart/mixed`. All other requests will fail with an HTTP 406 error code.
3124
+ 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.
3039
3125
 
3040
3126
  ```ruby
3041
3127
  class Twitter::API < Grape::API
@@ -3091,23 +3177,18 @@ end
3091
3177
  Built-in formatters are the following.
3092
3178
 
3093
3179
  * `:json`: use object's `to_json` when available, otherwise call `MultiJson.dump`
3094
- * `:xml`: use object's `to_xml` when available, usually via `MultiXml`, otherwise call `to_s`
3180
+ * `:xml`: use object's `to_xml` when available, usually via `MultiXml`
3095
3181
  * `:txt`: use object's `to_txt` when available, otherwise `to_s`
3096
3182
  * `:serializable_hash`: use object's `serializable_hash` when available, otherwise fallback to `:json`
3097
3183
  * `:binary`: data will be returned "as is"
3098
3184
 
3099
- If a body is present in a request to an API, with a Content-Type header value that is of an unsupported type a
3100
- "415 Unsupported Media Type" error code will be returned by Grape.
3185
+ 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.
3101
3186
 
3102
- Response statuses that indicate no content as defined by [Rack](https://github.com/rack)
3103
- [here](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
3104
- will bypass serialization and the body entity - though there should be none -
3105
- will not be modified.
3187
+ 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.
3106
3188
 
3107
3189
  ### JSONP
3108
3190
 
3109
- Grape supports JSONP via [Rack::JSONP](https://github.com/rack/rack-contrib), part of the
3110
- [rack-contrib](https://github.com/rack/rack-contrib) gem. Add `rack-contrib` to your `Gemfile`.
3191
+ 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`.
3111
3192
 
3112
3193
  ```ruby
3113
3194
  require 'rack/contrib'
@@ -3123,9 +3204,7 @@ end
3123
3204
 
3124
3205
  ### CORS
3125
3206
 
3126
- Grape supports CORS via [Rack::CORS](https://github.com/cyu/rack-cors), part of the
3127
- [rack-cors](https://github.com/cyu/rack-cors) gem. Add `rack-cors` to your `Gemfile`,
3128
- then use the middleware in your config.ru file.
3207
+ 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.
3129
3208
 
3130
3209
  ```ruby
3131
3210
  require 'rack/cors'
@@ -3143,8 +3222,7 @@ run Twitter::API
3143
3222
 
3144
3223
  ## Content-type
3145
3224
 
3146
- Content-type is set by the formatter. You can override the content-type of the response at runtime
3147
- by setting the `Content-Type` header.
3225
+ Content-type is set by the formatter. You can override the content-type of the response at runtime by setting the `Content-Type` header.
3148
3226
 
3149
3227
  ```ruby
3150
3228
  class API < Grape::API
@@ -3157,16 +3235,12 @@ end
3157
3235
 
3158
3236
  ## API Data Formats
3159
3237
 
3160
- Grape accepts and parses input data sent with the POST and PUT methods as described in the Parameters
3161
- section above. It also supports custom data formats. You must declare additional content-types via
3162
- `content_type` and optionally supply a parser via `parser` unless a parser is already available within
3163
- Grape to enable a custom format. Such a parser can be a function or a class.
3238
+ 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.
3164
3239
 
3165
3240
  With a parser, parsed data is available "as-is" in `env['api.request.body']`.
3166
3241
  Without a parser, data is available "as-is" and in `env['api.request.input']`.
3167
3242
 
3168
- The following example is a trivial parser that will assign any input with the "text/custom" content-type
3169
- to `:value`. The parameter will be available via `params[:value]` inside the API call.
3243
+ 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.
3170
3244
 
3171
3245
  ```ruby
3172
3246
  module CustomParser
@@ -3200,9 +3274,7 @@ Grape uses `JSON` and `ActiveSupport::XmlMini` for JSON and XML parsing by defau
3200
3274
 
3201
3275
  ## RESTful Model Representations
3202
3276
 
3203
- Grape supports a range of ways to present your data with some help from a generic `present` method,
3204
- which accepts two arguments: the object to be presented and the options associated with it. The options
3205
- hash may include `:with`, which defines the entity to expose.
3277
+ 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.
3206
3278
 
3207
3279
  ### Grape Entities
3208
3280
 
@@ -3281,8 +3353,7 @@ The response will be
3281
3353
  }
3282
3354
  ```
3283
3355
 
3284
- In addition to separately organizing entities, it may be useful to put them as namespaced
3285
- classes underneath the model they represent.
3356
+ In addition to separately organizing entities, it may be useful to put them as namespaced classes underneath the model they represent.
3286
3357
 
3287
3358
  ```ruby
3288
3359
  class Status
@@ -3296,11 +3367,7 @@ class Status
3296
3367
  end
3297
3368
  ```
3298
3369
 
3299
- If you organize your entities this way, Grape will automatically detect the `Entity` class and
3300
- use it to present your models. In this example, if you added `present Status.new` to your endpoint,
3301
- Grape will automatically detect that there is a `Status::Entity` class and use that as the
3302
- representative entity. This can still be overridden by using the `:with` option or an explicit
3303
- `represents` call.
3370
+ 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.
3304
3371
 
3305
3372
  You can present `hash` with `Grape::Presenters::Presenter` to keep things consistent.
3306
3373
 
@@ -3333,15 +3400,11 @@ You can use [Roar](https://github.com/apotonick/roar) to render HAL or Collectio
3333
3400
 
3334
3401
  ### Rabl
3335
3402
 
3336
- You can use [Rabl](https://github.com/nesquena/rabl) templates with the help of the
3337
- [grape-rabl](https://github.com/ruby-grape/grape-rabl) gem, which defines a custom Grape Rabl
3338
- formatter.
3403
+ 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.
3339
3404
 
3340
3405
  ### Active Model Serializers
3341
3406
 
3342
- You can use [Active Model Serializers](https://github.com/rails-api/active_model_serializers) serializers with the help of the
3343
- [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers) gem, which defines a custom Grape AMS
3344
- formatter.
3407
+ 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.
3345
3408
 
3346
3409
  ## Sending Raw or No Data
3347
3410
 
@@ -3381,9 +3444,7 @@ class API < Grape::API
3381
3444
  end
3382
3445
  ```
3383
3446
 
3384
- You can also set the response to a file with `sendfile`. This works with the
3385
- [Rack::Sendfile](https://www.rubydoc.info/gems/rack/Rack/Sendfile) middleware to optimally send
3386
- the file through your web server software.
3447
+ 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.
3387
3448
 
3388
3449
  ```ruby
3389
3450
  class API < Grape::API
@@ -3427,9 +3488,7 @@ end
3427
3488
 
3428
3489
  ### Basic Auth
3429
3490
 
3430
- Grape has built-in Basic authentication (the given `block`
3431
- is executed in the context of the current `Endpoint`). Authentication
3432
- applies to the current namespace and any children, but not parents.
3491
+ 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.
3433
3492
 
3434
3493
  ```ruby
3435
3494
  http_basic do |username, password|
@@ -3440,16 +3499,13 @@ end
3440
3499
 
3441
3500
  ### Register custom middleware for authentication
3442
3501
 
3443
- Grape can use custom Middleware for authentication. How to implement these
3444
- Middleware have a look at `Rack::Auth::Basic` or similar implementations.
3445
-
3502
+ Grape can use custom Middleware for authentication. How to implement these Middleware have a look at `Rack::Auth::Basic` or similar implementations.
3446
3503
 
3447
3504
  For registering a Middleware you need the following options:
3448
3505
 
3449
3506
  * `label` - the name for your authenticator to use it later
3450
3507
  * `MiddlewareClass` - the MiddlewareClass to use for authentication
3451
- * `option_lookup_proc` - A Proc with one Argument to lookup the options at
3452
- runtime (return value is an `Array` as Parameter for the Middleware).
3508
+ * `option_lookup_proc` - A Proc with one Argument to lookup the options at runtime (return value is an `Array` as Parameter for the Middleware).
3453
3509
 
3454
3510
  Example:
3455
3511
 
@@ -3473,7 +3529,7 @@ You can access the controller params, headers, and helpers through the context w
3473
3529
 
3474
3530
  Grape routes can be reflected at runtime. This can notably be useful for generating documentation.
3475
3531
 
3476
- 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`.
3532
+ 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`.
3477
3533
 
3478
3534
  ```ruby
3479
3535
  class TwitterAPI < Grape::API
@@ -3496,14 +3552,14 @@ TwitterAPI::routes[0].description # => 'Includes custom settings.'
3496
3552
  TwitterAPI::routes[0].settings[:custom] # => { key: 'value' }
3497
3553
  ```
3498
3554
 
3499
- Note that `Route#route_xyz` methods have been deprecated since 0.15.0.
3555
+ Note that `Route#route_xyz` methods have been deprecated since 0.15.0 and removed since 2.0.1.
3500
3556
 
3501
3557
  Please use `Route#xyz` instead.
3502
3558
 
3503
3559
  Note that difference of `Route#options` and `Route#settings`.
3504
3560
 
3505
- The `options` can be referred from your route, it should be set by specifing key and value on verb methods such as `get`, `post` and `put`.
3506
- The `settings` can also be referred from your route, but it should be set by specifing key and value on `route_setting`.
3561
+ The `options` can be referred from your route, it should be set by specifying key and value on verb methods such as `get`, `post` and `put`.
3562
+ The `settings` can also be referred from your route, but it should be set by specifying key and value on `route_setting`.
3507
3563
 
3508
3564
  ## Current Route and Endpoint
3509
3565
 
@@ -3516,15 +3572,12 @@ class MyAPI < Grape::API
3516
3572
  requires :id, type: Integer, desc: 'Identity.'
3517
3573
  end
3518
3574
  get 'params/:id' do
3519
- route.route_params[params[:id]] # yields the parameter description
3575
+ route.params[params[:id]] # yields the parameter description
3520
3576
  end
3521
3577
  end
3522
3578
  ```
3523
3579
 
3524
- The current endpoint responding to the request is `self` within the API block
3525
- or `env['api.endpoint']` elsewhere. The endpoint has some interesting properties,
3526
- such as `source` which gives you access to the original code block of the API
3527
- implementation. This can be particularly useful for building a logger middleware.
3580
+ 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.
3528
3581
 
3529
3582
  ```ruby
3530
3583
  class ApiLogger < Grape::Middleware::Base
@@ -3538,10 +3591,8 @@ end
3538
3591
 
3539
3592
  ## Before, After and Finally
3540
3593
 
3541
- Blocks can be executed before or after every API call, using `before`, `after`,
3542
- `before_validation` and `after_validation`.
3543
- If the API fails the `after` call will not be triggered, if you need code to execute for sure
3544
- use the `finally`.
3594
+ Blocks can be executed before or after every API call, using `before`, `after`, `before_validation` and `after_validation`.
3595
+ If the API fails the `after` call will not be triggered, if you need code to execute for sure use the `finally`.
3545
3596
 
3546
3597
  Before and after callbacks execute in the following order:
3547
3598
 
@@ -3555,13 +3606,9 @@ Before and after callbacks execute in the following order:
3555
3606
 
3556
3607
  Steps 4, 5 and 6 only happen if validation succeeds.
3557
3608
 
3558
- If a request for a resource is made with an unsupported HTTP method (returning
3559
- HTTP 405) only `before` callbacks will be executed. The remaining callbacks will
3560
- be bypassed.
3609
+ 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.
3561
3610
 
3562
- If a request for a resource is made that triggers the built-in `OPTIONS` handler,
3563
- only `before` and `after` callbacks will be executed. The remaining callbacks will
3564
- be bypassed.
3611
+ 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.
3565
3612
 
3566
3613
  For example, using a simple `before` block to set a header.
3567
3614
 
@@ -3706,11 +3753,7 @@ Instead of altering a response, you can also terminate and rewrite it from any c
3706
3753
 
3707
3754
  ## Anchoring
3708
3755
 
3709
- Grape by default anchors all request paths, which means that the request URL
3710
- should match from start to end to match, otherwise a `404 Not Found` is
3711
- returned. However, this is sometimes not what you want, because it is not always
3712
- known upfront what can be expected from the call. This is because Rack-mount by
3713
- default anchors requests to match from the start to the end, or not at all.
3756
+ 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.
3714
3757
  Rails solves this problem by using a `anchor: false` option in your routes.
3715
3758
  In Grape this option can be used as well when a method is defined.
3716
3759
 
@@ -3726,12 +3769,44 @@ class TwitterAPI < Grape::API
3726
3769
  end
3727
3770
  ```
3728
3771
 
3729
- This will match all paths starting with '/statuses/'. There is one caveat though:
3730
- the `params[:status]` parameter only holds the first part of the request url.
3731
- Luckily this can be circumvented by using the described above syntax for path
3732
- specification and using the `PATH_INFO` Rack environment variable, using
3733
- `env['PATH_INFO']`. This will hold everything that comes after the '/statuses/'
3734
- part.
3772
+ 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.
3773
+ 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.
3774
+
3775
+ ## Instance Variables
3776
+
3777
+ 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.
3778
+
3779
+ ```ruby
3780
+ class TwitterAPI < Grape::API
3781
+ before do
3782
+ @var = 1
3783
+ end
3784
+
3785
+ get '/' do
3786
+ puts @var # => 1
3787
+ raise
3788
+ end
3789
+
3790
+ rescue_from :all do
3791
+ puts @var # => 1
3792
+ end
3793
+ end
3794
+ ```
3795
+
3796
+ 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.
3797
+
3798
+ ```ruby
3799
+ class TwitterAPI < Grape::API
3800
+ get '/first' do
3801
+ @var = 1
3802
+ puts @var # => 1
3803
+ end
3804
+
3805
+ get '/second' do
3806
+ puts @var # => nil
3807
+ end
3808
+ end
3809
+ ```
3735
3810
 
3736
3811
  ## Using Custom Middleware
3737
3812
 
@@ -3940,8 +4015,7 @@ describe Twitter::API do
3940
4015
  end
3941
4016
  ```
3942
4017
 
3943
- In Rails, HTTP request tests would go into the `spec/requests` group. You may want your API code to go into
3944
- `app/api` - you can match that layout under `spec` by adding the following in `spec/rails_helper.rb`.
4018
+ 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`.
3945
4019
 
3946
4020
  ```ruby
3947
4021
  RSpec.configure do |config|
@@ -3975,10 +4049,7 @@ end
3975
4049
 
3976
4050
  ### Stubbing Helpers
3977
4051
 
3978
- Because helpers are mixed in based on the context when an endpoint is defined, it can
3979
- be difficult to stub or mock them for testing. The `Grape::Endpoint.before_each` method
3980
- can help by allowing you to define behavior on the endpoint that will run before every
3981
- request.
4052
+ 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.
3982
4053
 
3983
4054
  ```ruby
3984
4055
  describe 'an endpoint that needs helpers stubbed' do
@@ -4104,8 +4175,7 @@ Grape integrates with following third-party tools:
4104
4175
 
4105
4176
  ## Contributing to Grape
4106
4177
 
4107
- Grape is work of hundreds of contributors. You're encouraged to submit pull requests, propose
4108
- features and discuss issues.
4178
+ Grape is work of hundreds of contributors. You're encouraged to submit pull requests, propose features and discuss issues.
4109
4179
 
4110
4180
  See [CONTRIBUTING](CONTRIBUTING.md).
4111
4181