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.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -4
  3. data/Gemfile.lock +13 -13
  4. data/README.md +290 -12
  5. data/UPGRADING.md +68 -1
  6. data/gemfiles/rails_3.gemfile +1 -1
  7. data/lib/grape.rb +8 -2
  8. data/lib/grape/api.rb +40 -34
  9. data/lib/grape/dsl/configuration.rb +2 -115
  10. data/lib/grape/dsl/desc.rb +101 -0
  11. data/lib/grape/dsl/headers.rb +16 -0
  12. data/lib/grape/dsl/helpers.rb +5 -9
  13. data/lib/grape/dsl/inside_route.rb +3 -11
  14. data/lib/grape/dsl/logger.rb +20 -0
  15. data/lib/grape/dsl/parameters.rb +12 -10
  16. data/lib/grape/dsl/request_response.rb +17 -4
  17. data/lib/grape/dsl/routing.rb +24 -7
  18. data/lib/grape/dsl/settings.rb +8 -2
  19. data/lib/grape/endpoint.rb +30 -26
  20. data/lib/grape/error_formatter.rb +31 -0
  21. data/lib/grape/error_formatter/base.rb +0 -28
  22. data/lib/grape/error_formatter/json.rb +13 -2
  23. data/lib/grape/error_formatter/txt.rb +3 -1
  24. data/lib/grape/error_formatter/xml.rb +3 -1
  25. data/lib/grape/exceptions/base.rb +11 -4
  26. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  27. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  28. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  29. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  30. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  31. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  32. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
  33. data/lib/grape/exceptions/method_not_allowed.rb +10 -0
  34. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  35. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  36. data/lib/grape/exceptions/missing_option.rb +1 -1
  37. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  38. data/lib/grape/exceptions/unknown_options.rb +1 -1
  39. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  40. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  41. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  42. data/lib/grape/exceptions/validation.rb +2 -1
  43. data/lib/grape/formatter.rb +31 -0
  44. data/lib/grape/middleware/base.rb +28 -2
  45. data/lib/grape/middleware/error.rb +24 -1
  46. data/lib/grape/middleware/formatter.rb +4 -3
  47. data/lib/grape/middleware/versioner/param.rb +13 -2
  48. data/lib/grape/parser.rb +29 -0
  49. data/lib/grape/util/sendfile_response.rb +19 -0
  50. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  51. data/lib/grape/validations/params_scope.rb +39 -9
  52. data/lib/grape/validations/types.rb +16 -0
  53. data/lib/grape/validations/validators/all_or_none.rb +1 -1
  54. data/lib/grape/validations/validators/allow_blank.rb +2 -2
  55. data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
  56. data/lib/grape/validations/validators/base.rb +26 -0
  57. data/lib/grape/validations/validators/coerce.rb +16 -14
  58. data/lib/grape/validations/validators/default.rb +1 -1
  59. data/lib/grape/validations/validators/exactly_one_of.rb +10 -1
  60. data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
  61. data/lib/grape/validations/validators/presence.rb +1 -1
  62. data/lib/grape/validations/validators/regexp.rb +2 -2
  63. data/lib/grape/validations/validators/values.rb +2 -2
  64. data/lib/grape/version.rb +1 -1
  65. data/spec/grape/api/custom_validations_spec.rb +156 -21
  66. data/spec/grape/api/namespace_parameters_in_route_spec.rb +38 -0
  67. data/spec/grape/api/optional_parameters_in_route_spec.rb +43 -0
  68. data/spec/grape/api/required_parameters_in_route_spec.rb +37 -0
  69. data/spec/grape/api_spec.rb +118 -60
  70. data/spec/grape/dsl/configuration_spec.rb +0 -75
  71. data/spec/grape/dsl/desc_spec.rb +77 -0
  72. data/spec/grape/dsl/headers_spec.rb +32 -0
  73. data/spec/grape/dsl/inside_route_spec.rb +0 -18
  74. data/spec/grape/dsl/logger_spec.rb +26 -0
  75. data/spec/grape/dsl/parameters_spec.rb +13 -7
  76. data/spec/grape/dsl/request_response_spec.rb +17 -3
  77. data/spec/grape/dsl/routing_spec.rb +8 -1
  78. data/spec/grape/dsl/settings_spec.rb +42 -0
  79. data/spec/grape/endpoint_spec.rb +60 -9
  80. data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
  81. data/spec/grape/exceptions/validation_spec.rb +7 -0
  82. data/spec/grape/integration/rack_sendfile_spec.rb +44 -0
  83. data/spec/grape/middleware/base_spec.rb +100 -0
  84. data/spec/grape/middleware/exception_spec.rb +1 -2
  85. data/spec/grape/middleware/formatter_spec.rb +12 -2
  86. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
  87. data/spec/grape/middleware/versioner/header_spec.rb +11 -1
  88. data/spec/grape/middleware/versioner/param_spec.rb +105 -1
  89. data/spec/grape/validations/params_scope_spec.rb +77 -0
  90. data/spec/grape/validations/validators/allow_blank_spec.rb +277 -0
  91. data/spec/grape/validations/validators/coerce_spec.rb +91 -0
  92. data/spec/grape/validations/validators/default_spec.rb +6 -0
  93. data/spec/grape/validations/validators/presence_spec.rb +27 -0
  94. data/spec/grape/validations/validators/regexp_spec.rb +36 -0
  95. data/spec/grape/validations/validators/values_spec.rb +44 -0
  96. data/spec/grape/validations_spec.rb +149 -4
  97. data/spec/spec_helper.rb +1 -0
  98. metadata +26 -5
  99. data/lib/grape/formatter/base.rb +0 -31
  100. data/lib/grape/parser/base.rb +0 -29
  101. data/pkg/grape-0.13.0.gem +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3bc83c8aa5374d62068477b48daebd22f10c1761
4
- data.tar.gz: a91b6bf2854b1476b9565e3303efa4a67e431b17
3
+ metadata.gz: 6cfff6fd29d73a9f0c990999725d77521054eaed
4
+ data.tar.gz: 66ad4e087e432fe5c5d57641db83e5a78730d110
5
5
  SHA512:
6
- metadata.gz: 555a5eb54fc665f51ae44d4e3103e2c9b4ce92c3fc594c20cbb4001efdbe6515e95200fabe30455085b0a7b3ccaf178dbc1bb2ba75c6bdb5100a75521341614c
7
- data.tar.gz: e66803d3c8454744ea814d2d68e0e5fccaab9c544ddfeacf27c64b68aacd36821612875fa263b2d844c307e6dacc48655f98a594c4ecb1f87d595441abf56ee9
6
+ metadata.gz: 3949ea88f5dd3f57167aaf201789ac4619a334d778cba2b2c8e335a96060d76aa3f218234f5cc2597a2aea23d37bf29baed46505997fe4f7498231734af1b304
7
+ data.tar.gz: 0c903f1ba5a4d5f1cd4c75c9fd6fb10ef55aefe18543810aa81d8d14f3571133429aee42555972618f6f1608d83dbd66b3cf71df25758634770bc03902ea32a9
@@ -1,12 +1,40 @@
1
- 0.14.0 (12/17/2015)
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/putt/1190): Bypass formatting for statuses with no entity-body - [@tylerdooling](https://github.com/tylerdooling).
9
- * [#1188](https://github.com/ruby-grape/grape/putt/1188): Allow parameters with more than one type - [@dslh](https://github.com/dslh).
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/intridea/grape/pull/1101): Fix: Incorrect media-type `Accept` header now correctly returns 406 with `strict: true` - [@elliotlarson](https://github.com/elliotlarson).
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)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grape (0.14.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.1.0)
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.4.8)
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.1)
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.9)
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.3)
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.2.3.0)
87
- ast (>= 1.1, < 3.0)
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.0.0)
104
- rake (10.4.2)
105
- rb-fsevent (0.9.6)
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.0)
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 Grae [0.14.0](https://github.com/ruby-grape/grape/blob/v0.14.0/README.md).
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, :type => Hash do
605
+ requires :user, type: Hash do
604
606
  requires :first_name, type: String
605
607
  optional :last_name, type: String
606
- requires :address, :type => Hash do
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) gem.
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''#{URI.escape(filename)}"
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
- E.g. using `before`:
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
- The block applies to every API call within and below the current namespace:
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 whatever alias you are using) also work when using
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/spec_helper.rb`.
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 'should properly stub the helper' do
3015
+ it 'stubs the helper' do
2738
3016
  # ...
2739
3017
  end
2740
3018
  end