grape 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -4
- data/Gemfile.lock +13 -13
- data/README.md +290 -12
- data/UPGRADING.md +68 -1
- data/gemfiles/rails_3.gemfile +1 -1
- data/lib/grape.rb +8 -2
- data/lib/grape/api.rb +40 -34
- data/lib/grape/dsl/configuration.rb +2 -115
- data/lib/grape/dsl/desc.rb +101 -0
- data/lib/grape/dsl/headers.rb +16 -0
- data/lib/grape/dsl/helpers.rb +5 -9
- data/lib/grape/dsl/inside_route.rb +3 -11
- data/lib/grape/dsl/logger.rb +20 -0
- data/lib/grape/dsl/parameters.rb +12 -10
- data/lib/grape/dsl/request_response.rb +17 -4
- data/lib/grape/dsl/routing.rb +24 -7
- data/lib/grape/dsl/settings.rb +8 -2
- data/lib/grape/endpoint.rb +30 -26
- data/lib/grape/error_formatter.rb +31 -0
- data/lib/grape/error_formatter/base.rb +0 -28
- data/lib/grape/error_formatter/json.rb +13 -2
- data/lib/grape/error_formatter/txt.rb +3 -1
- data/lib/grape/error_formatter/xml.rb +3 -1
- data/lib/grape/exceptions/base.rb +11 -4
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_message_body.rb +1 -1
- data/lib/grape/exceptions/invalid_version_header.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
- data/lib/grape/exceptions/method_not_allowed.rb +10 -0
- data/lib/grape/exceptions/missing_group_type.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/missing_option.rb +1 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
- data/lib/grape/exceptions/unknown_options.rb +1 -1
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
- data/lib/grape/exceptions/validation.rb +2 -1
- data/lib/grape/formatter.rb +31 -0
- data/lib/grape/middleware/base.rb +28 -2
- data/lib/grape/middleware/error.rb +24 -1
- data/lib/grape/middleware/formatter.rb +4 -3
- data/lib/grape/middleware/versioner/param.rb +13 -2
- data/lib/grape/parser.rb +29 -0
- data/lib/grape/util/sendfile_response.rb +19 -0
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/params_scope.rb +39 -9
- data/lib/grape/validations/types.rb +16 -0
- data/lib/grape/validations/validators/all_or_none.rb +1 -1
- data/lib/grape/validations/validators/allow_blank.rb +2 -2
- data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
- data/lib/grape/validations/validators/base.rb +26 -0
- data/lib/grape/validations/validators/coerce.rb +16 -14
- data/lib/grape/validations/validators/default.rb +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -1
- data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
- data/lib/grape/validations/validators/presence.rb +1 -1
- data/lib/grape/validations/validators/regexp.rb +2 -2
- data/lib/grape/validations/validators/values.rb +2 -2
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/custom_validations_spec.rb +156 -21
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +38 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +43 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +37 -0
- data/spec/grape/api_spec.rb +118 -60
- data/spec/grape/dsl/configuration_spec.rb +0 -75
- data/spec/grape/dsl/desc_spec.rb +77 -0
- data/spec/grape/dsl/headers_spec.rb +32 -0
- data/spec/grape/dsl/inside_route_spec.rb +0 -18
- data/spec/grape/dsl/logger_spec.rb +26 -0
- data/spec/grape/dsl/parameters_spec.rb +13 -7
- data/spec/grape/dsl/request_response_spec.rb +17 -3
- data/spec/grape/dsl/routing_spec.rb +8 -1
- data/spec/grape/dsl/settings_spec.rb +42 -0
- data/spec/grape/endpoint_spec.rb +60 -9
- data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
- data/spec/grape/exceptions/validation_spec.rb +7 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +44 -0
- data/spec/grape/middleware/base_spec.rb +100 -0
- data/spec/grape/middleware/exception_spec.rb +1 -2
- data/spec/grape/middleware/formatter_spec.rb +12 -2
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
- data/spec/grape/middleware/versioner/header_spec.rb +11 -1
- data/spec/grape/middleware/versioner/param_spec.rb +105 -1
- data/spec/grape/validations/params_scope_spec.rb +77 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +277 -0
- data/spec/grape/validations/validators/coerce_spec.rb +91 -0
- data/spec/grape/validations/validators/default_spec.rb +6 -0
- data/spec/grape/validations/validators/presence_spec.rb +27 -0
- data/spec/grape/validations/validators/regexp_spec.rb +36 -0
- data/spec/grape/validations/validators/values_spec.rb +44 -0
- data/spec/grape/validations_spec.rb +149 -4
- data/spec/spec_helper.rb +1 -0
- metadata +26 -5
- data/lib/grape/formatter/base.rb +0 -31
- data/lib/grape/parser/base.rb +0 -29
- data/pkg/grape-0.13.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cfff6fd29d73a9f0c990999725d77521054eaed
|
4
|
+
data.tar.gz: 66ad4e087e432fe5c5d57641db83e5a78730d110
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3949ea88f5dd3f57167aaf201789ac4619a334d778cba2b2c8e335a96060d76aa3f218234f5cc2597a2aea23d37bf29baed46505997fe4f7498231734af1b304
|
7
|
+
data.tar.gz: 0c903f1ba5a4d5f1cd4c75c9fd6fb10ef55aefe18543810aa81d8d14f3571133429aee42555972618f6f1608d83dbd66b3cf71df25758634770bc03902ea32a9
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,40 @@
|
|
1
|
-
0.
|
1
|
+
0.15.0 (3/8/2016)
|
2
|
+
=================
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* [#1227](https://github.com/ruby-grape/grape/pull/1227): Store `message_key` on `Grape::Exceptions::Validation` - [@stjhimy](https://github.com/sthimy).
|
7
|
+
* [#1232](https://github.com/ruby-grape/grape/pull/1232): Helpers are now available inside `rescue_from` - [@namusyaka](https://github.com/namusyaka).
|
8
|
+
* [#1237](https://github.com/ruby-grape/grape/pull/1237): Allow multiple parameters in `given`, which behaves as if the scopes were nested in the inputted order - [@ochagata](https://github.com/ochagata).
|
9
|
+
* [#1238](https://github.com/ruby-grape/grape/pull/1238): Call `after` of middleware on error - [@namusyaka](https://github.com/namusyaka).
|
10
|
+
* [#1243](https://github.com/ruby-grape/grape/pull/1243): Add `header` support for middleware - [@namusyaka](https://github.com/namusyaka).
|
11
|
+
* [#1252](https://github.com/ruby-grape/grape/pull/1252): Allow default to be a subset or equal to allowed values without raising IncompatibleOptionValues - [@jeradphelps](https://github.com/jeradphelps).
|
12
|
+
* [#1255](https://github.com/ruby-grape/grape/pull/1255): Allow param type definition in `route_param` - [@namusyaka](https://github.com/namusyaka).
|
13
|
+
* [#1257](https://github.com/ruby-grape/grape/pull/1257): Allow Proc, Symbol or String in `rescue_from with: ...` - [@namusyaka](https://github.com/namusyaka).
|
14
|
+
* [#1280](https://github.com/ruby-grape/grape/pull/1280): Support `Rack::Sendfile` middleware - [@lfidnl](https://github.com/lfidnl).
|
15
|
+
* [#1285](https://github.com/ruby-grape/grape/pull/1285): Add a warning for errors appearing in `after` callbacks - [@gregormelhorn](https://github.com/gregormelhorn).
|
16
|
+
* [#1295](https://github.com/ruby-grape/grape/pull/1295): Add custom validation messages for parameter exceptions - [@railsmith](https://github.com/railsmith).
|
17
|
+
|
18
|
+
#### Fixes
|
19
|
+
|
20
|
+
* [#1216](https://github.com/ruby-grape/grape/pull/1142): Fix JSON error response when calling `error!` with non-Strings - [@jrforrest](https://github.com/jrforrest).
|
21
|
+
* [#1225](https://github.com/ruby-grape/grape/pull/1225): Fix `given` with nested params not returning correct declared params - [@JanStevens](https://github.com/JanStevens).
|
22
|
+
* [#1249](https://github.com/ruby-grape/grape/pull/1249): Don't fail even if invalid type value is passed to default validator - [@namusyaka](https://github.com/namusyaka).
|
23
|
+
* [#1266](https://github.com/ruby-grape/grape/pull/1266): Fix `Allow` header including `OPTIONS` when `do_not_route_options!` is active - [@arempe93](https://github.com/arempe93).
|
24
|
+
* [#1270](https://github.com/ruby-grape/grape/pull/1270): Fix `param` versioning with a custom parameter - [@wshatch](https://github.com/wshatch).
|
25
|
+
* [#1282](https://github.com/ruby-grape/grape/pull/1282): Fix specs circular dependency - [@304](https://github.com/304).
|
26
|
+
* [#1283](https://github.com/ruby-grape/grape/pull/1283): Fix 500 error for xml format when method is not allowed - [@304](https://github.com/304).
|
27
|
+
* [#1197](https://github.com/ruby-grape/grape/pull/1290): Fix using JSON and Array[JSON] as groups when parameter is optional - [@lukeivers](https://github.com/lukeivers).
|
28
|
+
|
29
|
+
0.14.0 (12/07/2015)
|
2
30
|
===================
|
3
31
|
|
4
32
|
#### Features
|
5
33
|
|
6
34
|
* [#1218](https://github.com/ruby-grape/grape/pull/1218): Provide array index context in errors - [@towanda](https://github.com/towanda).
|
7
35
|
* [#1196](https://github.com/ruby-grape/grape/pull/1196): Allow multiple `before_each` blocks - [@huynhquancam](https://github.com/huynhquancam).
|
8
|
-
* [#1190](https://github.com/ruby-grape/grape/
|
9
|
-
* [#1188](https://github.com/ruby-grape/grape/
|
36
|
+
* [#1190](https://github.com/ruby-grape/grape/pull/1190): Bypass formatting for statuses with no entity-body - [@tylerdooling](https://github.com/tylerdooling).
|
37
|
+
* [#1188](https://github.com/ruby-grape/grape/pull/1188): Allow parameters with more than one type - [@dslh](https://github.com/dslh).
|
10
38
|
* [#1179](https://github.com/ruby-grape/grape/pull/1179): Allow all RFC6838 valid characters in header vendor - [@suan](https://github.com/suan).
|
11
39
|
* [#1170](https://github.com/ruby-grape/grape/pull/1170): Allow dashes and periods in header vendor - [@suan](https://github.com/suan).
|
12
40
|
* [#1167](https://github.com/ruby-grape/grape/pull/1167): Convenience wrapper `type: File` for validating multipart file parameters - [@dslh](https://github.com/dslh).
|
@@ -23,7 +51,7 @@
|
|
23
51
|
* [#1142](https://github.com/ruby-grape/grape/pull/1142): Makes #declared unavailable to before filters - [@jrforrest](https://github.com/jrforrest).
|
24
52
|
* [#1114](https://github.com/ruby-grape/grape/pull/1114): Fix regression which broke identical endpoints with different versions - [@suan](https://github.com/suan).
|
25
53
|
* [#1109](https://github.com/ruby-grape/grape/pull/1109): Memoize Virtus attribute and fix memory leak - [@marshall-lee](https://github.com/marshall-lee).
|
26
|
-
* [#1101](https://github.com/
|
54
|
+
* [#1101](https://github.com/ruby-grape/grape/pull/1101): Fix: Incorrect media-type `Accept` header now correctly returns 406 with `strict: true` - [@elliotlarson](https://github.com/elliotlarson).
|
27
55
|
* [#1108](https://github.com/ruby-grape/grape/pull/1039): Raise a warning when `desc` is called with options hash and block - [@rngtng](https://github.com/rngtng).
|
28
56
|
|
29
57
|
0.13.0 (8/10/2015)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grape (0.
|
4
|
+
grape (0.15.0)
|
5
5
|
activesupport
|
6
6
|
builder
|
7
7
|
hashie (>= 2.1.0)
|
@@ -15,7 +15,7 @@ PATH
|
|
15
15
|
GEM
|
16
16
|
remote: https://rubygems.org/
|
17
17
|
specs:
|
18
|
-
activesupport (4.2.5)
|
18
|
+
activesupport (4.2.5.1)
|
19
19
|
i18n (~> 0.7)
|
20
20
|
json (~> 1.7, >= 1.7.7)
|
21
21
|
minitest (~> 5.1)
|
@@ -25,7 +25,7 @@ GEM
|
|
25
25
|
bundler
|
26
26
|
rake
|
27
27
|
thor (>= 0.14.0)
|
28
|
-
ast (2.
|
28
|
+
ast (2.2.0)
|
29
29
|
astrolabe (1.3.1)
|
30
30
|
parser (~> 2.2)
|
31
31
|
axiom-types (0.1.1)
|
@@ -45,7 +45,7 @@ GEM
|
|
45
45
|
ffi (1.9.10)
|
46
46
|
formatador (0.2.5)
|
47
47
|
git-version-bump (0.15.1)
|
48
|
-
grape-entity (0.
|
48
|
+
grape-entity (0.5.0)
|
49
49
|
activesupport
|
50
50
|
multi_json (>= 1.3.2)
|
51
51
|
guard (2.13.0)
|
@@ -67,24 +67,24 @@ GEM
|
|
67
67
|
rubocop (~> 0.20)
|
68
68
|
hashie (3.4.3)
|
69
69
|
i18n (0.7.0)
|
70
|
-
ice_nine (0.11.
|
70
|
+
ice_nine (0.11.2)
|
71
71
|
json (1.8.3)
|
72
72
|
listen (3.0.5)
|
73
73
|
rb-fsevent (>= 0.9.3)
|
74
74
|
rb-inotify (>= 0.9)
|
75
|
-
lumberjack (1.0.
|
75
|
+
lumberjack (1.0.10)
|
76
76
|
maruku (0.7.2)
|
77
77
|
method_source (0.8.2)
|
78
78
|
mime-types (2.99)
|
79
|
-
minitest (5.8.
|
79
|
+
minitest (5.8.4)
|
80
80
|
multi_json (1.11.2)
|
81
81
|
multi_xml (0.5.5)
|
82
82
|
nenv (0.2.0)
|
83
83
|
notiffany (0.0.8)
|
84
84
|
nenv (~> 0.1)
|
85
85
|
shellany (~> 0.0)
|
86
|
-
parser (2.
|
87
|
-
ast (
|
86
|
+
parser (2.3.0.6)
|
87
|
+
ast (~> 2.2)
|
88
88
|
powerpack (0.1.1)
|
89
89
|
pry (0.10.3)
|
90
90
|
coderay (~> 1.1.0)
|
@@ -100,9 +100,9 @@ GEM
|
|
100
100
|
rack (>= 1.0.0)
|
101
101
|
rack-test (0.6.3)
|
102
102
|
rack (>= 1.0)
|
103
|
-
rainbow (2.
|
104
|
-
rake (10.
|
105
|
-
rb-fsevent (0.9.
|
103
|
+
rainbow (2.1.0)
|
104
|
+
rake (10.5.0)
|
105
|
+
rb-fsevent (0.9.7)
|
106
106
|
rb-inotify (0.9.5)
|
107
107
|
ffi (>= 0.5.0)
|
108
108
|
rspec (3.4.0)
|
@@ -114,7 +114,7 @@ GEM
|
|
114
114
|
rspec-expectations (3.4.0)
|
115
115
|
diff-lcs (>= 1.2.0, < 2.0)
|
116
116
|
rspec-support (~> 3.4.0)
|
117
|
-
rspec-mocks (3.4.
|
117
|
+
rspec-mocks (3.4.1)
|
118
118
|
diff-lcs (>= 1.2.0, < 2.0)
|
119
119
|
rspec-support (~> 3.4.0)
|
120
120
|
rspec-support (3.4.1)
|
data/README.md
CHANGED
@@ -41,6 +41,7 @@
|
|
41
41
|
- [Custom Validators](#custom-validators)
|
42
42
|
- [Validation Errors](#validation-errors)
|
43
43
|
- [I18n](#i18n)
|
44
|
+
- [Custom Validation Messages](#custom-validation-messages)
|
44
45
|
- [Headers](#headers)
|
45
46
|
- [Routes](#routes)
|
46
47
|
- [Helpers](#helpers)
|
@@ -73,6 +74,7 @@
|
|
73
74
|
- [Before and After](#before-and-after)
|
74
75
|
- [Anchoring](#anchoring)
|
75
76
|
- [Using Custom Middleware](#using-custom-middleware)
|
77
|
+
- [Grape Middleware](#grape-middleware)
|
76
78
|
- [Rails Middleware](#rails-middleware)
|
77
79
|
- [Remote IP](#remote-ip)
|
78
80
|
- [Writing Tests](#writing-tests)
|
@@ -99,7 +101,7 @@ content negotiation, versioning and much more.
|
|
99
101
|
|
100
102
|
## Stable Release
|
101
103
|
|
102
|
-
You're reading the documentation for the stable release of
|
104
|
+
You're reading the documentation for the stable release of Grape, 0.15.0.
|
103
105
|
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
104
106
|
|
105
107
|
## Project Resources
|
@@ -600,10 +602,10 @@ It also works on nested hashes:
|
|
600
602
|
format :json
|
601
603
|
|
602
604
|
params do
|
603
|
-
requires :user, :
|
605
|
+
requires :user, type: Hash do
|
604
606
|
requires :first_name, type: String
|
605
607
|
optional :last_name, type: String
|
606
|
-
requires :address, :
|
608
|
+
requires :address, type: Hash do
|
607
609
|
requires :city, type: String
|
608
610
|
optional :region, type: String
|
609
611
|
end
|
@@ -1146,6 +1148,19 @@ namespace :statuses do
|
|
1146
1148
|
end
|
1147
1149
|
```
|
1148
1150
|
|
1151
|
+
You can also define a route parameter type by passing to `route_param`'s options.
|
1152
|
+
|
1153
|
+
```ruby
|
1154
|
+
namespace :arithmetic do
|
1155
|
+
route_param :n, type: Integer do
|
1156
|
+
desc 'Returns in power'
|
1157
|
+
get 'power' do
|
1158
|
+
params[:n] ** params[:n]
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
```
|
1163
|
+
|
1149
1164
|
### Custom Validators
|
1150
1165
|
|
1151
1166
|
```ruby
|
@@ -1182,6 +1197,35 @@ params do
|
|
1182
1197
|
end
|
1183
1198
|
```
|
1184
1199
|
|
1200
|
+
You can also create custom validation that use request to validate the attribute. For example if you want to have parameters that are available to only admins, you can do the following.
|
1201
|
+
|
1202
|
+
```ruby
|
1203
|
+
class Admin < Grape::Validations::Base
|
1204
|
+
def validate(request)
|
1205
|
+
# return if the param we are checking was not in request
|
1206
|
+
# @attrs is a list containing the attribute we are currently validating
|
1207
|
+
# in our sample case this method once will get called with
|
1208
|
+
# @attrs being [:admin_field] and once with @attrs being [:admin_false_field]
|
1209
|
+
return unless request.params.key? @attrs.first
|
1210
|
+
# check if admin flag is set to true
|
1211
|
+
return unless @option
|
1212
|
+
# check if user is admin or not
|
1213
|
+
# as an example get a token from request and check if it's admin or not
|
1214
|
+
fail Grape::Exceptions::Validation, params: @attrs, message: 'Can not set admin-only field.' unless request.headers['X-Access-Token'] == 'admin'
|
1215
|
+
end
|
1216
|
+
end
|
1217
|
+
```
|
1218
|
+
|
1219
|
+
And use it in your endpoint definition as:
|
1220
|
+
|
1221
|
+
```ruby
|
1222
|
+
params do
|
1223
|
+
optional :admin_field, type: String, admin: true
|
1224
|
+
optional :non_admin_field, type: String
|
1225
|
+
optional :admin_false_field, type: String, admin: false
|
1226
|
+
end
|
1227
|
+
```
|
1228
|
+
|
1185
1229
|
### Validation Errors
|
1186
1230
|
|
1187
1231
|
Validation and coercion errors are collected and an exception of type `Grape::Exceptions::ValidationErrors` is raised. If the exception goes uncaught it will respond with a status of 400 and an error message. The validation errors are grouped by parameter name and can be accessed via `Grape::Exceptions::ValidationErrors#errors`.
|
@@ -1222,6 +1266,119 @@ end
|
|
1222
1266
|
Grape supports I18n for parameter-related error messages, but will fallback to English if
|
1223
1267
|
translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
|
1224
1268
|
|
1269
|
+
### Custom Validation messages
|
1270
|
+
|
1271
|
+
Grape supports custom validation messages for parameter-related and coerce-related error messages.
|
1272
|
+
|
1273
|
+
#### `presence`, `allow_blank`, `values`, `regexp`
|
1274
|
+
|
1275
|
+
```ruby
|
1276
|
+
params do
|
1277
|
+
requires :name, values: { value: 1..10, message: 'not in range from 1 to 10' }, allow_blank: { value: false, message: 'cannot be blank' }, regexp: { value: /^[a-z]+$/, message: 'format is invalid' }, message: 'is required'
|
1278
|
+
end
|
1279
|
+
```
|
1280
|
+
#### `all_or_none_of`
|
1281
|
+
|
1282
|
+
```ruby
|
1283
|
+
params do
|
1284
|
+
optional :beer
|
1285
|
+
optional :wine
|
1286
|
+
optional :juice
|
1287
|
+
all_or_none_of :beer, :wine, :juice, message: "all params are required or none is required"
|
1288
|
+
end
|
1289
|
+
```
|
1290
|
+
|
1291
|
+
#### `mutually_exclusive`
|
1292
|
+
|
1293
|
+
```ruby
|
1294
|
+
params do
|
1295
|
+
optional :beer
|
1296
|
+
optional :wine
|
1297
|
+
optional :juice
|
1298
|
+
mutually_exclusive :beer, :wine, :juice, message: "are mutually exclusive cannot pass both params"
|
1299
|
+
end
|
1300
|
+
```
|
1301
|
+
#### `exactly_one_of`
|
1302
|
+
|
1303
|
+
```ruby
|
1304
|
+
params do
|
1305
|
+
optional :beer
|
1306
|
+
optional :wine
|
1307
|
+
optional :juice
|
1308
|
+
exactly_one_of :beer, :wine, :juice, message: {exactly_one: "are missing, exactly one parameter is required", mutual_exclusion: "are mutually exclusive, exactly one parameter is required"}
|
1309
|
+
end
|
1310
|
+
```
|
1311
|
+
#### `at_least_one_of`
|
1312
|
+
|
1313
|
+
```ruby
|
1314
|
+
params do
|
1315
|
+
optional :beer
|
1316
|
+
optional :wine
|
1317
|
+
optional :juice
|
1318
|
+
at_least_one_of :beer, :wine, :juice, message: "are missing, please specify at least one param"
|
1319
|
+
end
|
1320
|
+
```
|
1321
|
+
#### `Coerce`
|
1322
|
+
|
1323
|
+
```ruby
|
1324
|
+
params do
|
1325
|
+
requires :int, type: {value: Integer, message: "type cast is invalid" }
|
1326
|
+
end
|
1327
|
+
```
|
1328
|
+
#### `With Lambdas`
|
1329
|
+
|
1330
|
+
```ruby
|
1331
|
+
params do
|
1332
|
+
requires :name, values: { value: -> { (1..10).to_a }, message: 'not in range from 1 to 10' }
|
1333
|
+
end
|
1334
|
+
```
|
1335
|
+
#### `Pass symbols for i18n translations`
|
1336
|
+
|
1337
|
+
You can pass a symbol if you want i18n translations for your custom validation messages.
|
1338
|
+
|
1339
|
+
```ruby
|
1340
|
+
params do
|
1341
|
+
requires :name, message: :name_required
|
1342
|
+
end
|
1343
|
+
```
|
1344
|
+
```ruby
|
1345
|
+
# en.yml
|
1346
|
+
|
1347
|
+
en:
|
1348
|
+
grape:
|
1349
|
+
errors:
|
1350
|
+
format: ! '%{attributes} %{message}'
|
1351
|
+
messages:
|
1352
|
+
name_required: 'must be present'
|
1353
|
+
```
|
1354
|
+
|
1355
|
+
#### `Overriding attribute names`
|
1356
|
+
|
1357
|
+
You can also override attribute names.
|
1358
|
+
|
1359
|
+
```ruby
|
1360
|
+
# en.yml
|
1361
|
+
|
1362
|
+
en:
|
1363
|
+
grape:
|
1364
|
+
errors:
|
1365
|
+
format: ! '%{attributes} %{message}'
|
1366
|
+
messages:
|
1367
|
+
name_required: 'must be present'
|
1368
|
+
attributes:
|
1369
|
+
name: 'Oops! Name'
|
1370
|
+
```
|
1371
|
+
Will produce 'Oops! Name must be present'
|
1372
|
+
|
1373
|
+
#### `With Default`
|
1374
|
+
|
1375
|
+
You cannot set a custom message option for Default as it requires interpolation `%{option1}: %{value1} is incompatible with %{option2}: %{value2}`. You can change the default error message for Default by changing the `incompatible_option_values` message key inside [en.yml](lib/grape/locale/en.yml)
|
1376
|
+
|
1377
|
+
```ruby
|
1378
|
+
params do
|
1379
|
+
requires :name, values: { value: -> { (1..10).to_a }, message: 'not in range from 1 to 10' }, default: 5
|
1380
|
+
end
|
1381
|
+
```
|
1225
1382
|
## Headers
|
1226
1383
|
|
1227
1384
|
Request headers are available through the `headers` helper or from `env` in their original form.
|
@@ -1542,6 +1699,12 @@ You can abort the execution of an API method by raising errors with `error!`.
|
|
1542
1699
|
error! 'Access Denied', 401
|
1543
1700
|
```
|
1544
1701
|
|
1702
|
+
Anything that responds to `#to_s` can be given as a first argument to `error!`.
|
1703
|
+
|
1704
|
+
```ruby
|
1705
|
+
error! :not_found, 404
|
1706
|
+
```
|
1707
|
+
|
1545
1708
|
You can also return JSON formatted objects by raising error! and passing a hash
|
1546
1709
|
instead of a message.
|
1547
1710
|
|
@@ -1562,7 +1725,7 @@ end
|
|
1562
1725
|
|
1563
1726
|
The following example specifies the entity to use in the `http_codes` definition.
|
1564
1727
|
|
1565
|
-
```
|
1728
|
+
```ruby
|
1566
1729
|
desc 'My Route' do
|
1567
1730
|
failure [[408, 'Unauthorized', API::Error]]
|
1568
1731
|
end
|
@@ -1731,8 +1894,41 @@ rescue_from RuntimeError, rescue_subclasses: false do |e|
|
|
1731
1894
|
end
|
1732
1895
|
```
|
1733
1896
|
|
1897
|
+
Helpers are also available inside `rescue_from`.
|
1898
|
+
|
1899
|
+
```ruby
|
1900
|
+
class Twitter::API < Grape::API
|
1901
|
+
format :json
|
1902
|
+
helpers do
|
1903
|
+
def server_error!
|
1904
|
+
error!({ error: 'Server error.' }, 500, { 'Content-Type' => 'text/error' })
|
1905
|
+
end
|
1906
|
+
end
|
1907
|
+
|
1908
|
+
rescue_from :all do |e|
|
1909
|
+
server_error!
|
1910
|
+
end
|
1911
|
+
end
|
1912
|
+
```
|
1913
|
+
|
1734
1914
|
The `rescue_from` block must return a `Rack::Response` object, call `error!` or re-raise an exception.
|
1735
1915
|
|
1916
|
+
The `with` keyword is available as `rescue_from` options, it can be passed method name or Proc object.
|
1917
|
+
|
1918
|
+
```ruby
|
1919
|
+
class Twitter::API < Grape::API
|
1920
|
+
format :json
|
1921
|
+
helpers do
|
1922
|
+
def server_error!
|
1923
|
+
error!({ error: 'Server error.' }, 500, { 'Content-Type' => 'text/error' })
|
1924
|
+
end
|
1925
|
+
end
|
1926
|
+
|
1927
|
+
rescue_from :all, with: :server_error!
|
1928
|
+
rescue_from ArgumentError, with: -> { Rack::Response.new('rescued with a method', 400) }
|
1929
|
+
end
|
1930
|
+
```
|
1931
|
+
|
1736
1932
|
#### Unrescuable Exceptions
|
1737
1933
|
|
1738
1934
|
`Grape::Exceptions::InvalidVersionHeader`, which is raised when the version in the request header doesn't match the currently evaluated version for the endpoint, will _never_ be rescued from a `rescue_from` block (even a `rescue_from :all`) This is because Grape relies on Rack to catch that error and try the next versioned-route for cases where there exist identical Grape endpoints with different versions.
|
@@ -1801,7 +1997,7 @@ class API < Grape::API
|
|
1801
1997
|
end
|
1802
1998
|
```
|
1803
1999
|
|
1804
|
-
For similar to Rails request logging try the [grape_logging](https://github.com/aserafin/grape_logging)
|
2000
|
+
For similar to Rails request logging try the [grape_logging](https://github.com/aserafin/grape_logging) or [grape-middleware-logger](https://github.com/ridiculous/grape-middleware-logger) gems.
|
1805
2001
|
|
1806
2002
|
## API Formats
|
1807
2003
|
|
@@ -1885,7 +2081,7 @@ class Twitter::API < Grape::API
|
|
1885
2081
|
filename = params[:file][:filename]
|
1886
2082
|
content_type MIME::Types.type_for(filename)[0].to_s
|
1887
2083
|
env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
|
1888
|
-
header 'Content-Disposition', "attachment; filename*=UTF-8''#{
|
2084
|
+
header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(filename)}"
|
1889
2085
|
params[:file][:tempfile].read
|
1890
2086
|
end
|
1891
2087
|
end
|
@@ -2274,6 +2470,30 @@ class API < Grape::API
|
|
2274
2470
|
end
|
2275
2471
|
```
|
2276
2472
|
|
2473
|
+
If you want to take advantage of `Rack::Sendfile`, which intercepts responses whose body is
|
2474
|
+
being served from a file and replaces it with a server specific X-Sendfile header, specify `to_path`
|
2475
|
+
method in your file streamer class which returns path of served file:
|
2476
|
+
|
2477
|
+
```ruby
|
2478
|
+
class FileStreamer
|
2479
|
+
# ...
|
2480
|
+
|
2481
|
+
def to_path
|
2482
|
+
@file_path
|
2483
|
+
end
|
2484
|
+
|
2485
|
+
# ...
|
2486
|
+
end
|
2487
|
+
```
|
2488
|
+
|
2489
|
+
Note: don't forget turn on `Rack::Sendfile` middleware in your API:
|
2490
|
+
|
2491
|
+
```ruby
|
2492
|
+
class API < Grape::API
|
2493
|
+
use Rack::Sendfile
|
2494
|
+
end
|
2495
|
+
```
|
2496
|
+
|
2277
2497
|
## Authentication
|
2278
2498
|
|
2279
2499
|
### Basic and Digest Auth
|
@@ -2399,7 +2619,9 @@ Before and after callbacks execute in the following order:
|
|
2399
2619
|
|
2400
2620
|
Steps 4, 5 and 6 only happen if validation succeeds.
|
2401
2621
|
|
2402
|
-
|
2622
|
+
#### Examples
|
2623
|
+
|
2624
|
+
Using a simple `before` block to set a header
|
2403
2625
|
|
2404
2626
|
```ruby
|
2405
2627
|
before do
|
@@ -2407,7 +2629,9 @@ before do
|
|
2407
2629
|
end
|
2408
2630
|
```
|
2409
2631
|
|
2410
|
-
|
2632
|
+
**Namespaces**
|
2633
|
+
|
2634
|
+
Callbacks apply to each API call within and below the current namespace:
|
2411
2635
|
|
2412
2636
|
```ruby
|
2413
2637
|
class MyAPI < Grape::API
|
@@ -2441,8 +2665,7 @@ GET /foo # 'root - foo - blah'
|
|
2441
2665
|
GET /foo/bar # 'root - foo - bar - blah'
|
2442
2666
|
```
|
2443
2667
|
|
2444
|
-
Params on a `namespace` (or
|
2445
|
-
`before_validation` or `after_validation`:
|
2668
|
+
Params on a `namespace` (or whichever alias you are using) will also be available when using `before_validation` or `after_validation`:
|
2446
2669
|
|
2447
2670
|
```ruby
|
2448
2671
|
class MyAPI < Grape::API
|
@@ -2469,6 +2692,8 @@ GET /123 # 'Fixnum'
|
|
2469
2692
|
GET /foo # 400 error - 'blah is invalid'
|
2470
2693
|
```
|
2471
2694
|
|
2695
|
+
**Versioning**
|
2696
|
+
|
2472
2697
|
When a callback is defined within a version block, it's only called for the routes defined in that block.
|
2473
2698
|
|
2474
2699
|
```ruby
|
@@ -2502,6 +2727,33 @@ GET /foo/v1 # 'v1-hello'
|
|
2502
2727
|
GET /foo/v2 # 'v2-hello'
|
2503
2728
|
```
|
2504
2729
|
|
2730
|
+
**Altering Responses**
|
2731
|
+
|
2732
|
+
Using `present` in any callback allows you to add data to a response:
|
2733
|
+
|
2734
|
+
```ruby
|
2735
|
+
class MyAPI < Grape::API
|
2736
|
+
format :json
|
2737
|
+
|
2738
|
+
after_validation do
|
2739
|
+
present :name, params[:name] if params[:name]
|
2740
|
+
end
|
2741
|
+
|
2742
|
+
get '/greeting' do
|
2743
|
+
present :greeting, 'Hello!'
|
2744
|
+
end
|
2745
|
+
end
|
2746
|
+
```
|
2747
|
+
|
2748
|
+
The behaviour is then:
|
2749
|
+
|
2750
|
+
```bash
|
2751
|
+
GET /greeting # {"greeting":"Hello!"}
|
2752
|
+
GET /greeting?name=Alan # {"name":"Alan","greeting":"Hello!"}
|
2753
|
+
```
|
2754
|
+
|
2755
|
+
Instead of altering a response, you can also terminate and rewrite it from any callback using `error!`, including `after`. This will cause all subsequent steps in the process to not be called. **This includes the actual api call and any callbacks**
|
2756
|
+
|
2505
2757
|
## Anchoring
|
2506
2758
|
|
2507
2759
|
Grape by default anchors all request paths, which means that the request URL
|
@@ -2533,6 +2785,32 @@ part.
|
|
2533
2785
|
|
2534
2786
|
## Using Custom Middleware
|
2535
2787
|
|
2788
|
+
### Grape Middleware
|
2789
|
+
|
2790
|
+
You can make a custom middleware by using `Grape::Middleware::Base`.
|
2791
|
+
It's inherited from some grape official middlewares in fact.
|
2792
|
+
|
2793
|
+
For example, you can write a middleware to log application exception.
|
2794
|
+
|
2795
|
+
```ruby
|
2796
|
+
class LoggingError < Grape::Middleware::Base
|
2797
|
+
def after
|
2798
|
+
return unless @app_response && @app_response[0] == 500
|
2799
|
+
env['rack.logger'].error("Raised error on #{env['PATH_INFO']}")
|
2800
|
+
end
|
2801
|
+
end
|
2802
|
+
```
|
2803
|
+
|
2804
|
+
Your middleware can overwrite application response as follows, except error case.
|
2805
|
+
|
2806
|
+
```ruby
|
2807
|
+
class Overwriter < Grape::Middleware::Base
|
2808
|
+
def after
|
2809
|
+
[200, { 'Content-Type' => 'text/plain' }, ['Overwrited.']]
|
2810
|
+
end
|
2811
|
+
end
|
2812
|
+
```
|
2813
|
+
|
2536
2814
|
### Rails Middleware
|
2537
2815
|
|
2538
2816
|
Note that when you're using Grape mounted on Rails you don't have to use Rails middleware because it's already included into your middleware stack.
|
@@ -2683,7 +2961,7 @@ end
|
|
2683
2961
|
```
|
2684
2962
|
|
2685
2963
|
In Rails, HTTP request tests would go into the `spec/requests` group. You may want your API code to go into
|
2686
|
-
`app/api` - you can match that layout under `spec` by adding the following in `spec/
|
2964
|
+
`app/api` - you can match that layout under `spec` by adding the following in `spec/rails_helper.rb`.
|
2687
2965
|
|
2688
2966
|
```ruby
|
2689
2967
|
RSpec.configure do |config|
|
@@ -2734,7 +3012,7 @@ describe 'an endpoint that needs helpers stubbed' do
|
|
2734
3012
|
Grape::Endpoint.before_each nil
|
2735
3013
|
end
|
2736
3014
|
|
2737
|
-
it '
|
3015
|
+
it 'stubs the helper' do
|
2738
3016
|
# ...
|
2739
3017
|
end
|
2740
3018
|
end
|