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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +151 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +404 -334
- data/UPGRADING.md +279 -7
- data/grape.gemspec +8 -8
- data/lib/grape/api/instance.rb +34 -66
- data/lib/grape/api.rb +47 -70
- data/lib/grape/content_types.rb +13 -10
- data/lib/grape/cookies.rb +31 -24
- data/lib/grape/dry_types.rb +0 -2
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/desc.rb +49 -44
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +8 -4
- data/lib/grape/dsl/inside_route.rb +67 -54
- data/lib/grape/dsl/parameters.rb +10 -9
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/dsl/routing.rb +34 -17
- data/lib/grape/dsl/validations.rb +13 -0
- data/lib/grape/endpoint.rb +120 -118
- data/lib/grape/{util/env.rb → env.rb} +0 -5
- data/lib/grape/error_formatter/base.rb +51 -21
- data/lib/grape/error_formatter/json.rb +7 -15
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +11 -17
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +5 -25
- data/lib/grape/exceptions/base.rb +18 -30
- data/lib/grape/exceptions/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/validation.rb +5 -6
- data/lib/grape/exceptions/validation_array_errors.rb +1 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -6
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
- data/lib/grape/extensions/hash.rb +7 -2
- data/lib/grape/extensions/hashie/mash.rb +3 -5
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +4 -6
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +7 -25
- data/lib/grape/{util/json.rb → json.rb} +1 -3
- data/lib/grape/locale/en.yml +46 -42
- data/lib/grape/middleware/auth/base.rb +11 -34
- data/lib/grape/middleware/auth/dsl.rb +23 -31
- data/lib/grape/middleware/base.rb +41 -23
- data/lib/grape/middleware/error.rb +77 -76
- data/lib/grape/middleware/formatter.rb +48 -79
- data/lib/grape/middleware/globals.rb +1 -3
- data/lib/grape/middleware/stack.rb +26 -37
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +74 -0
- data/lib/grape/middleware/versioner/header.rb +59 -126
- data/lib/grape/middleware/versioner/param.rb +4 -25
- data/lib/grape/middleware/versioner/path.rb +10 -34
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/namespace.rb +4 -5
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +38 -60
- data/lib/grape/request.rb +161 -30
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +45 -31
- data/lib/grape/router/route.rb +28 -57
- data/lib/grape/router.rb +56 -43
- data/lib/grape/util/base_inheritable.rb +4 -4
- data/lib/grape/util/cache.rb +0 -3
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_values.rb +0 -2
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +1 -6
- data/lib/grape/util/strict_hash_configuration.rb +3 -3
- data/lib/grape/validations/attributes_doc.rb +38 -36
- data/lib/grape/validations/attributes_iterator.rb +1 -0
- data/lib/grape/validations/contract_scope.rb +34 -0
- data/lib/grape/validations/params_scope.rb +36 -32
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +9 -15
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +0 -2
- data/lib/grape/validations/types/set_coercer.rb +0 -3
- data/lib/grape/validations/types.rb +0 -3
- data/lib/grape/validations/validator_factory.rb +2 -2
- data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
- data/lib/grape/validations/validators/base.rb +8 -11
- data/lib/grape/validations/validators/coerce_validator.rb +1 -1
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +6 -2
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
- data/lib/grape/validations/validators/except_values_validator.rb +2 -2
- data/lib/grape/validations/validators/length_validator.rb +49 -0
- data/lib/grape/validations/validators/presence_validator.rb +1 -1
- data/lib/grape/validations/validators/regexp_validator.rb +2 -2
- data/lib/grape/validations/validators/values_validator.rb +20 -57
- data/lib/grape/validations.rb +8 -21
- data/lib/grape/version.rb +1 -1
- data/lib/grape/{util/xml.rb → xml.rb} +1 -1
- data/lib/grape.rb +42 -274
- metadata +45 -44
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/http/headers.rb +0 -71
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/validations/types/build_coercer.rb +0 -94
data/README.md
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|

|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/grape)
|
4
|
-
[](https://codeclimate.com/github/ruby-grape/grape)
|
4
|
+
[](https://github.com/ruby-grape/grape/actions/workflows/test.yml)
|
6
5
|
[](https://coveralls.io/github/ruby-grape/grape?branch=master)
|
7
|
-
[](https://inch-ci.org/github/ruby-grape/grape)
|
8
|
-
[](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
|
-
- [
|
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
|
-
- [
|
34
|
-
|
35
|
-
|
36
|
-
|
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,
|
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?
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
559
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
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
|
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]
|
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 `
|
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
|
-
|
1518
|
-
|
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
|
-
|
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
|
1584
|
+
with(type: String, regexp: /w+/, documentation: { in: 'body' }) do
|
1534
1585
|
requires :first_name, desc: 'First name'
|
1535
|
-
|
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
|
-
|
2993
|
-
* `GET /hello.xls`
|
2994
|
-
|
2995
|
-
|
2996
|
-
|
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
|
-
|
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
|
-
|
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
|
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 `
|
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
|
3506
|
-
The `settings` can also be referred from your route, but it should be set by
|
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.
|
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
|
-
`
|
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 `
|
3731
|
-
|
3732
|
-
|
3733
|
-
|
3734
|
-
|
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
|
|