grape 0.5.0 → 0.6.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 +15 -0
- data/.travis.yml +2 -6
- data/CHANGELOG.md +20 -0
- data/README.md +43 -11
- data/lib/grape.rb +6 -0
- data/lib/grape/api.rb +27 -14
- data/lib/grape/endpoint.rb +33 -34
- data/lib/grape/exceptions/base.rb +4 -2
- data/lib/grape/exceptions/validation.rb +13 -3
- data/lib/grape/exceptions/validation_errors.rb +42 -0
- data/lib/grape/http/request.rb +1 -1
- data/lib/grape/locale/en.yml +4 -3
- data/lib/grape/middleware/auth/base.rb +30 -0
- data/lib/grape/middleware/auth/basic.rb +2 -19
- data/lib/grape/middleware/auth/digest.rb +2 -19
- data/lib/grape/middleware/error.rb +10 -1
- data/lib/grape/middleware/formatter.rb +1 -1
- data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +2 -2
- data/lib/grape/path.rb +72 -0
- data/lib/grape/route.rb +6 -1
- data/lib/grape/validations.rb +25 -8
- data/lib/grape/validations/coerce.rb +1 -2
- data/lib/grape/validations/presence.rb +6 -2
- data/lib/grape/validations/regexp.rb +1 -2
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +71 -6
- data/spec/grape/entity_spec.rb +5 -5
- data/spec/grape/middleware/base_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +3 -3
- data/spec/grape/middleware/versioner/header_spec.rb +25 -0
- data/spec/grape/path_spec.rb +219 -0
- data/spec/grape/validations/coerce_spec.rb +31 -13
- data/spec/grape/validations/presence_spec.rb +12 -12
- data/spec/grape/validations/zh-CN.yml +4 -3
- data/spec/grape/validations_spec.rb +154 -10
- data/spec/support/versioned_helpers.rb +5 -2
- metadata +10 -45
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Y2ZhNWZiZWQ4YjIwNmY5MDk1NmQxODgxM2FiZDA0NTE3ZDlmZmNiYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MTE5MjU2MWY2MWZlNGI1ODQzNDExMDZjOTNmZjRiYzc3ZDY4ODZlMg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MDlhYjA4YWQ1OThhMGFhNTc3ZjUwNzI4N2FiNmY2ZmNlOGM3MjQ5YjE2OWMy
|
10
|
+
NzcxODEwZmY3Y2I5ZmVkOTk5ZWViMTNkZmE3NGM3MjMyOTAzZTdmMTg5MWZm
|
11
|
+
ZmI1Njk0ZjRlMGIwOGFkY2EzZDJhZTMxMDQ0MzcyMDM4Y2UxMGY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OWU4MGUxOGJkYzRjYzhkZmQyMzFkMWU1NTk3ZTllMTRkZDkyOTA0YjcwODg3
|
14
|
+
YWNiNWY0ZDQzZWUxNmI4MmYxZGQzOWJmMTFiZDg0YTFiNzMyYzA5ODBhMDYz
|
15
|
+
ZWRiN2FmY2FhM2FjNjQ1ZWM2NjMwNWI1YmU1Y2NhYjA1NGI2MDg=
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
0.6.0 (9/16/2013)
|
2
|
+
=================
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* Grape is no longer tested against Ruby 1.8.7.
|
7
|
+
* [#442](https://github.com/intridea/grape/issues/442): Enable incrementally building on top of a previous API version - [@dblock](https://github.com/dblock).
|
8
|
+
* [#442](https://github.com/intridea/grape/issues/442): API `version` can now take an array of multiple versions - [@dblock](https://github.com/dblock).
|
9
|
+
* [#444](https://github.com/intridea/grape/issues/444): Added `:en` as fallback locale for I18n - [@aew](https://github.com/aew).
|
10
|
+
* [#448](https://github.com/intridea/grape/pull/448): Adding POST style parameters for DELETE requests - [@dquimper](https://github.com/dquimper).
|
11
|
+
* [#450](https://github.com/intridea/grape/pull/450): Added option to pass an exception handler lambda as an argument to `rescue_from` - [@robertopedroso](https://github.com/robertopedroso).
|
12
|
+
* [#443](https://github.com/intridea/grape/pull/443): Let `requires` and `optional` take blocks that initialize new scopes - [@asross](https://github.com/asross).
|
13
|
+
* [#452](https://github.com/intridea/grape/pull/452): Added `with` as a hash option to specify handlers for `rescue_from` and `error_formatter` [@robertopedroso](https://github.com/robertopedroso).
|
14
|
+
* [#433](https://github.com/intridea/grape/issues/433), [#462](https://github.com/intridea/grape/issues/462): API change: validation errors are now collected and `Grape::Exceptions::ValidationErrors` is raised - [@stevschmid](https://github.com/stevschmid).
|
15
|
+
* Your contribution here.
|
16
|
+
|
17
|
+
#### Fixes
|
18
|
+
|
19
|
+
* [#428](https://github.com/intridea/grape/issues/428): Removes memoization from `Grape::Request` params to prevent middleware from freezing parameter values before `Formatter` can get them - [@mbleigh](https://github.com/mbleigh).
|
20
|
+
|
1
21
|
0.5.0 (6/14/2013)
|
2
22
|
=================
|
3
23
|
|
data/README.md
CHANGED
@@ -10,6 +10,10 @@ content negotiation, versioning and much more.
|
|
10
10
|
|
11
11
|
[![Build Status](https://travis-ci.org/intridea/grape.png?branch=master)](http://travis-ci.org/intridea/grape) [![Code Climate](https://codeclimate.com/github/intridea/grape.png)](https://codeclimate.com/github/intridea/grape)
|
12
12
|
|
13
|
+
## Stable Release
|
14
|
+
|
15
|
+
You're reading the documentation for the stable release of Grape, 0.6.0.
|
16
|
+
|
13
17
|
## Project Resources
|
14
18
|
|
15
19
|
* Need help? [Grape Google Group](http://groups.google.com/group/ruby-grape)
|
@@ -221,7 +225,7 @@ version 'v1', using: :header, vendor: 'twitter'
|
|
221
225
|
|
222
226
|
Using this versioning strategy, clients should pass the desired version in the HTTP `Accept` head.
|
223
227
|
|
224
|
-
curl -H Accept
|
228
|
+
curl -H Accept:application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
|
225
229
|
|
226
230
|
By default, the first matching version is used when no `Accept` header is
|
227
231
|
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
|
@@ -236,7 +240,7 @@ version 'v1', using: :accept_version_header
|
|
236
240
|
|
237
241
|
Using this versioning strategy, clients should pass the desired version in the HTTP `Accept-Version` header.
|
238
242
|
|
239
|
-
curl -H "Accept-Version
|
243
|
+
curl -H "Accept-Version:v1" http://localhost:9292/statuses/public_timeline
|
240
244
|
|
241
245
|
By default, the first matching version is used when no `Accept-Version` header is
|
242
246
|
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
|
@@ -329,6 +333,9 @@ params do
|
|
329
333
|
group :media do
|
330
334
|
requires :url
|
331
335
|
end
|
336
|
+
optional :audio do
|
337
|
+
requires :mp3
|
338
|
+
end
|
332
339
|
end
|
333
340
|
put ':id' do
|
334
341
|
# params[:id] is an Integer
|
@@ -346,8 +353,9 @@ params do
|
|
346
353
|
end
|
347
354
|
```
|
348
355
|
|
349
|
-
Parameters can be nested using `group
|
350
|
-
`params[:media][:url]` is required along with `params[:id]
|
356
|
+
Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
|
357
|
+
In the above example, this means `params[:media][:url]` is required along with `params[:id]`,
|
358
|
+
and `params[:audio][:mp3]` is required only if `params[:audio]` is present.
|
351
359
|
|
352
360
|
### Namespace Validation and Coercion
|
353
361
|
|
@@ -379,7 +387,7 @@ The `namespace` method has a number of aliases, including: `group`, `resource`,
|
|
379
387
|
class AlphaNumeric < Grape::Validations::Validator
|
380
388
|
def validate_param!(attr_name, params)
|
381
389
|
unless params[attr_name] =~ /^[[:alnum:]]+$/
|
382
|
-
|
390
|
+
raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message: "must consist of alpha-numeric characters"
|
383
391
|
end
|
384
392
|
end
|
385
393
|
end
|
@@ -397,7 +405,7 @@ You can also create custom classes that take parameters.
|
|
397
405
|
class Length < Grape::Validations::SingleOptionValidator
|
398
406
|
def validate_param!(attr_name, params)
|
399
407
|
unless params[attr_name].length <= @option
|
400
|
-
|
408
|
+
raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message: "must be at the most #{@option} characters long"
|
401
409
|
end
|
402
410
|
end
|
403
411
|
end
|
@@ -411,20 +419,28 @@ end
|
|
411
419
|
|
412
420
|
### Validation Errors
|
413
421
|
|
414
|
-
|
422
|
+
Validation and coercion errors are collected and an exception of type `Grape::Exceptions::ValidationErrors` is raised.
|
415
423
|
If the exception goes uncaught it will respond with a status of 400 and an error message.
|
416
|
-
You can rescue a `Grape::Exceptions::
|
424
|
+
You can rescue a `Grape::Exceptions::ValidationErrors` and respond with a custom response.
|
417
425
|
|
418
426
|
```ruby
|
419
|
-
rescue_from Grape::Exceptions::
|
427
|
+
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
420
428
|
Rack::Response.new({
|
421
429
|
'status' => e.status,
|
422
430
|
'message' => e.message,
|
423
|
-
'
|
431
|
+
'errors' => e.errors
|
424
432
|
}.to_json, e.status)
|
425
433
|
end
|
426
434
|
```
|
427
435
|
|
436
|
+
The validation errors are grouped by parameter name and can be accessed via ``Grape::Exceptions::ValidationErrors#errors``.
|
437
|
+
|
438
|
+
### I18n
|
439
|
+
|
440
|
+
Grape supports I18n for parameter-related error messages, but will fallback to English if
|
441
|
+
translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
|
442
|
+
|
443
|
+
|
428
444
|
## Headers
|
429
445
|
|
430
446
|
Request headers are available through the `headers` helper or from `env` in their original form.
|
@@ -629,9 +645,23 @@ You can also return JSON formatted objects by raising error! and passing a hash
|
|
629
645
|
instead of a message.
|
630
646
|
|
631
647
|
```ruby
|
632
|
-
error!
|
648
|
+
error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
|
633
649
|
```
|
634
650
|
|
651
|
+
### Handling 404
|
652
|
+
|
653
|
+
For Grape to handle all the 404s for your API, it can be useful to use a catch-all.
|
654
|
+
In its simplest form, it can be like:
|
655
|
+
|
656
|
+
```ruby
|
657
|
+
route :any, '*path' do
|
658
|
+
error! # or something else
|
659
|
+
end
|
660
|
+
```
|
661
|
+
|
662
|
+
It is very crucial to __define this endpoint at the very end of your API__, as it
|
663
|
+
literally accepts every request.
|
664
|
+
|
635
665
|
## Exception Handling
|
636
666
|
|
637
667
|
Grape can be told to rescue all exceptions and return them in the API format.
|
@@ -1045,6 +1075,8 @@ You can use any Hypermedia representer, including [Roar](https://github.com/apot
|
|
1045
1075
|
Roar renders JSON and works with the built-in Grape JSON formatter. Add `Roar::Representer::JSON`
|
1046
1076
|
into your models or call `to_json` explicitly in your API implementation.
|
1047
1077
|
|
1078
|
+
Other alternatives include `ActiveModel::Serializers` via [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers).
|
1079
|
+
|
1048
1080
|
### Rabl
|
1049
1081
|
|
1050
1082
|
You can use [Rabl](https://github.com/nesquena/rabl) templates with the help of the
|
data/lib/grape.rb
CHANGED
@@ -22,8 +22,12 @@ I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
|
|
22
22
|
module Grape
|
23
23
|
autoload :API, 'grape/api'
|
24
24
|
autoload :Endpoint, 'grape/endpoint'
|
25
|
+
|
25
26
|
autoload :Route, 'grape/route'
|
26
27
|
autoload :Namespace, 'grape/namespace'
|
28
|
+
|
29
|
+
autoload :Path, 'grape/path'
|
30
|
+
|
27
31
|
autoload :Cookies, 'grape/cookies'
|
28
32
|
autoload :Validations, 'grape/validations'
|
29
33
|
autoload :Request, 'grape/http/request'
|
@@ -31,6 +35,7 @@ module Grape
|
|
31
35
|
module Exceptions
|
32
36
|
autoload :Base, 'grape/exceptions/base'
|
33
37
|
autoload :Validation, 'grape/exceptions/validation'
|
38
|
+
autoload :ValidationErrors, 'grape/exceptions/validation_errors'
|
34
39
|
autoload :MissingVendorOption, 'grape/exceptions/missing_vendor_option'
|
35
40
|
autoload :MissingMimeType, 'grape/exceptions/missing_mime_type'
|
36
41
|
autoload :MissingOption, 'grape/exceptions/missing_option'
|
@@ -70,6 +75,7 @@ module Grape
|
|
70
75
|
|
71
76
|
module Auth
|
72
77
|
autoload :OAuth2, 'grape/middleware/auth/oauth2'
|
78
|
+
autoload :Base, 'grape/middleware/auth/base'
|
73
79
|
autoload :Basic, 'grape/middleware/auth/basic'
|
74
80
|
autoload :Digest, 'grape/middleware/auth/digest'
|
75
81
|
end
|
data/lib/grape/api.rb
CHANGED
@@ -6,14 +6,8 @@ module Grape
|
|
6
6
|
extend Validations::ClassMethods
|
7
7
|
|
8
8
|
class << self
|
9
|
-
attr_reader :route_set
|
10
|
-
attr_reader :versions
|
11
|
-
attr_reader :routes
|
12
|
-
attr_reader :settings
|
9
|
+
attr_reader :endpoints, :instance, :routes, :route_set, :settings, :versions
|
13
10
|
attr_writer :logger
|
14
|
-
attr_reader :endpoints
|
15
|
-
attr_reader :mountings
|
16
|
-
attr_reader :instance
|
17
11
|
|
18
12
|
def logger(logger = nil)
|
19
13
|
if logger
|
@@ -27,7 +21,6 @@ module Grape
|
|
27
21
|
@settings = Grape::Util::HashStack.new
|
28
22
|
@route_set = Rack::Mount::RouteSet.new
|
29
23
|
@endpoints = []
|
30
|
-
@mountings = []
|
31
24
|
@routes = nil
|
32
25
|
reset_validations!
|
33
26
|
end
|
@@ -158,8 +151,14 @@ module Grape
|
|
158
151
|
new_formatter ? set(:default_error_formatter, new_formatter) : settings[:default_error_formatter]
|
159
152
|
end
|
160
153
|
|
161
|
-
def error_formatter(format,
|
162
|
-
|
154
|
+
def error_formatter(format, options)
|
155
|
+
if options.is_a?(Hash) && options.has_key?(:with)
|
156
|
+
formatter = options[:with]
|
157
|
+
else
|
158
|
+
formatter = options
|
159
|
+
end
|
160
|
+
|
161
|
+
settings.imbue(:error_formatters, format.to_sym => formatter)
|
163
162
|
end
|
164
163
|
|
165
164
|
# Specify additional content-types, e.g.:
|
@@ -195,13 +194,27 @@ module Grape
|
|
195
194
|
# @param [Block] block Execution block to handle the given exception.
|
196
195
|
# @param [Hash] options Options for the rescue usage.
|
197
196
|
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
|
197
|
+
# @param [Proc] handler Execution proc to handle the given exception as an
|
198
|
+
# alternative to passing a block
|
198
199
|
def rescue_from(*args, &block)
|
199
|
-
if
|
200
|
+
if args.last.is_a?(Proc)
|
201
|
+
handler = args.pop
|
202
|
+
elsif block_given?
|
203
|
+
handler = block
|
204
|
+
end
|
205
|
+
|
206
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
207
|
+
if options.has_key?(:with)
|
208
|
+
handler ||= proc { options[:with] }
|
209
|
+
end
|
210
|
+
|
211
|
+
if handler
|
200
212
|
args.each do |arg|
|
201
|
-
imbue(:rescue_handlers, { arg =>
|
213
|
+
imbue(:rescue_handlers, { arg => handler })
|
202
214
|
end
|
203
215
|
end
|
204
|
-
|
216
|
+
|
217
|
+
imbue(:rescue_options, options)
|
205
218
|
set(:rescue_all, true) and return if args.include?(:all)
|
206
219
|
imbue(:rescued_errors, args)
|
207
220
|
end
|
@@ -422,7 +435,7 @@ module Grape
|
|
422
435
|
end
|
423
436
|
|
424
437
|
def cascade(value = nil)
|
425
|
-
value.nil? ?
|
438
|
+
value.nil? ?
|
426
439
|
(settings.has_key?(:cascade) ? !! settings[:cascade] : true) :
|
427
440
|
set(:cascade, value)
|
428
441
|
end
|
data/lib/grape/endpoint.rb
CHANGED
@@ -33,27 +33,34 @@ module Grape
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def initialize(settings, options = {}, &block)
|
36
|
+
require_option(options, :path)
|
37
|
+
require_option(options, :method)
|
38
|
+
|
36
39
|
@settings = settings
|
40
|
+
@options = options
|
41
|
+
|
42
|
+
@options[:path] = Array(options[:path])
|
43
|
+
@options[:path] << '/' if options[:path].empty?
|
44
|
+
|
45
|
+
@options[:method] = Array(options[:method])
|
46
|
+
@options[:route_options] ||= {}
|
47
|
+
|
37
48
|
if block_given?
|
38
|
-
method_name = [
|
39
|
-
options[:method],
|
40
|
-
Namespace.joined_space(settings),
|
41
|
-
settings.gather(:mount_path).join("/"),
|
42
|
-
Array(options[:path]).join("/")
|
43
|
-
].join(" ")
|
44
49
|
@source = block
|
45
50
|
@block = self.class.generate_api_method(method_name, &block)
|
46
51
|
end
|
47
|
-
|
48
|
-
|
49
|
-
raise Grape::Exceptions::MissingOption.new(:path) unless options.key?(:path)
|
50
|
-
options[:path] = Array(options[:path])
|
51
|
-
options[:path] = ['/'] if options[:path].empty?
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
options
|
54
|
+
def require_option(options, key)
|
55
|
+
options.has_key?(key) or raise Grape::Exceptions::MissingOption.new(key)
|
56
|
+
end
|
55
57
|
|
56
|
-
|
58
|
+
def method_name
|
59
|
+
[ options[:method],
|
60
|
+
Namespace.joined_space(settings),
|
61
|
+
settings.gather(:mount_path).join('/'),
|
62
|
+
options[:path].join('/')
|
63
|
+
].join(" ")
|
57
64
|
end
|
58
65
|
|
59
66
|
def routes
|
@@ -120,24 +127,7 @@ module Grape
|
|
120
127
|
end
|
121
128
|
|
122
129
|
def prepare_path(path)
|
123
|
-
|
124
|
-
parts << settings[:mount_path].to_s.split("/") if settings[:mount_path]
|
125
|
-
parts << settings[:root_prefix].to_s.split("/") if settings[:root_prefix]
|
126
|
-
|
127
|
-
uses_path_versioning = settings[:version] && settings[:version_options][:using] == :path
|
128
|
-
namespace_is_empty = namespace && (namespace.to_s =~ /^\s*$/ || namespace.to_s == '/')
|
129
|
-
path_is_empty = path && (path.to_s =~ /^\s*$/ || path.to_s == '/')
|
130
|
-
|
131
|
-
parts << ':version' if uses_path_versioning
|
132
|
-
if ! uses_path_versioning || (! namespace_is_empty || ! path_is_empty)
|
133
|
-
parts << namespace.to_s if namespace
|
134
|
-
parts << path.to_s if path
|
135
|
-
format_suffix = '(.:format)'
|
136
|
-
else
|
137
|
-
format_suffix = '(/.:format)'
|
138
|
-
end
|
139
|
-
parts = parts.flatten.select { |part| part != '/' }
|
140
|
-
Rack::Mount::Utils.normalize_path(parts.join('/') + format_suffix)
|
130
|
+
Path.prepare(path, namespace, settings)
|
141
131
|
end
|
142
132
|
|
143
133
|
def namespace
|
@@ -391,8 +381,17 @@ module Grape
|
|
391
381
|
run_filters befores
|
392
382
|
|
393
383
|
# Retieve validations from this namespace and all parent namespaces.
|
384
|
+
validation_errors = []
|
394
385
|
settings.gather(:validations).each do |validator|
|
395
|
-
|
386
|
+
begin
|
387
|
+
validator.validate!(params)
|
388
|
+
rescue Grape::Exceptions::Validation => e
|
389
|
+
validation_errors << e
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
if validation_errors.any?
|
394
|
+
raise Grape::Exceptions::ValidationErrors, errors: validation_errors
|
396
395
|
end
|
397
396
|
|
398
397
|
run_filters after_validations
|
@@ -433,7 +432,7 @@ module Grape
|
|
433
432
|
|
434
433
|
if settings[:version]
|
435
434
|
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]), {
|
436
|
-
:versions => settings[:version],
|
435
|
+
:versions => settings[:version] ? settings[:version].flatten : nil,
|
437
436
|
:version_options => settings[:version_options],
|
438
437
|
:prefix => settings[:root_prefix]
|
439
438
|
}
|
@@ -4,6 +4,7 @@ module Grape
|
|
4
4
|
|
5
5
|
BASE_MESSAGES_KEY = 'grape.errors.messages'
|
6
6
|
BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
|
7
|
+
FALLBACK_LOCALE = :en
|
7
8
|
|
8
9
|
attr_reader :status, :message, :headers
|
9
10
|
|
@@ -54,11 +55,12 @@ module Grape
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def translate_message(key, options = {})
|
57
|
-
translate("#{BASE_MESSAGES_KEY}.#{key}", {:default => '' }.merge(options))
|
58
|
+
translate("#{BASE_MESSAGES_KEY}.#{key}", { :default => '' }.merge(options))
|
58
59
|
end
|
59
60
|
|
60
61
|
def translate(key, options = {})
|
61
|
-
::I18n.translate(key, options)
|
62
|
+
message = ::I18n.translate(key, options)
|
63
|
+
message.present? ? message : ::I18n.translate(key, options.merge({:locale => FALLBACK_LOCALE}))
|
62
64
|
end
|
63
65
|
|
64
66
|
end
|
@@ -6,11 +6,21 @@ module Grape
|
|
6
6
|
attr_accessor :param
|
7
7
|
|
8
8
|
def initialize(args = {})
|
9
|
-
|
10
|
-
|
11
|
-
args[:message] = translate_message(args[:message_key]
|
9
|
+
raise "Param is missing:" unless args.has_key? :param
|
10
|
+
@param = args[:param]
|
11
|
+
args[:message] = translate_message(args[:message_key]) if args.has_key? :message_key
|
12
12
|
super
|
13
13
|
end
|
14
|
+
|
15
|
+
# remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
16
|
+
# and headers when converting a validation error to json or string
|
17
|
+
def as_json(*a)
|
18
|
+
self.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
message
|
23
|
+
end
|
14
24
|
end
|
15
25
|
end
|
16
26
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'grape/exceptions/base'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Exceptions
|
5
|
+
class ValidationErrors < Grape::Exceptions::Base
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :errors
|
9
|
+
|
10
|
+
def initialize(args = {})
|
11
|
+
@errors = {}
|
12
|
+
args[:errors].each do |validation_error|
|
13
|
+
@errors[validation_error.param] ||= []
|
14
|
+
@errors[validation_error.param] << validation_error
|
15
|
+
end
|
16
|
+
super message: full_messages.join(', '), status: 400
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
errors.each_pair do |attribute, errors|
|
21
|
+
errors.each do |error|
|
22
|
+
yield attribute, error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def full_messages
|
30
|
+
map { |attribute, error| full_message(attribute, error) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def full_message(attribute, error)
|
34
|
+
I18n.t(:"grape.errors.format", {
|
35
|
+
default: "%{attribute} %{message}",
|
36
|
+
attribute: translate_attribute(attribute),
|
37
|
+
message: error.message
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|