grape 0.6.1 → 0.7.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 +9 -9
- data/.gitignore +7 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +3 -3
- data/CHANGELOG.md +42 -3
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +4 -4
- data/README.md +312 -52
- data/Rakefile +6 -1
- data/UPGRADING.md +124 -0
- data/lib/grape.rb +2 -0
- data/lib/grape/api.rb +95 -44
- data/lib/grape/cookies.rb +0 -2
- data/lib/grape/endpoint.rb +63 -39
- data/lib/grape/error_formatter/base.rb +0 -3
- data/lib/grape/error_formatter/json.rb +0 -2
- data/lib/grape/error_formatter/txt.rb +0 -2
- data/lib/grape/error_formatter/xml.rb +0 -2
- data/lib/grape/exceptions/base.rb +0 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +0 -3
- data/lib/grape/exceptions/invalid_formatter.rb +0 -3
- data/lib/grape/exceptions/invalid_versioner_option.rb +0 -4
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +0 -2
- data/lib/grape/exceptions/missing_mime_type.rb +0 -4
- data/lib/grape/exceptions/missing_option.rb +0 -3
- data/lib/grape/exceptions/missing_vendor_option.rb +0 -3
- data/lib/grape/exceptions/unknown_options.rb +0 -4
- data/lib/grape/exceptions/unknown_validator.rb +0 -2
- data/lib/grape/exceptions/validation_errors.rb +6 -5
- data/lib/grape/formatter/base.rb +0 -3
- data/lib/grape/formatter/json.rb +0 -2
- data/lib/grape/formatter/serializable_hash.rb +15 -16
- data/lib/grape/formatter/txt.rb +0 -2
- data/lib/grape/formatter/xml.rb +0 -2
- data/lib/grape/http/request.rb +2 -4
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/oauth2.rb +15 -6
- data/lib/grape/middleware/base.rb +7 -7
- data/lib/grape/middleware/error.rb +11 -6
- data/lib/grape/middleware/formatter.rb +80 -78
- data/lib/grape/middleware/globals.rb +13 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
- data/lib/grape/middleware/versioner/header.rb +5 -3
- data/lib/grape/middleware/versioner/param.rb +2 -4
- data/lib/grape/middleware/versioner/path.rb +3 -4
- data/lib/grape/namespace.rb +0 -1
- data/lib/grape/parser/base.rb +0 -3
- data/lib/grape/parser/json.rb +0 -2
- data/lib/grape/parser/xml.rb +0 -2
- data/lib/grape/path.rb +1 -3
- data/lib/grape/route.rb +0 -3
- data/lib/grape/util/hash_stack.rb +1 -1
- data/lib/grape/validations.rb +72 -22
- data/lib/grape/validations/coerce.rb +5 -4
- data/lib/grape/validations/default.rb +5 -3
- data/lib/grape/validations/presence.rb +1 -1
- data/lib/grape/validations/regexp.rb +0 -2
- data/lib/grape/validations/values.rb +2 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +385 -96
- data/spec/grape/endpoint_spec.rb +162 -15
- data/spec/grape/entity_spec.rb +25 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
- data/spec/grape/middleware/auth/oauth2_spec.rb +60 -15
- data/spec/grape/middleware/base_spec.rb +3 -8
- data/spec/grape/middleware/error_spec.rb +2 -2
- data/spec/grape/middleware/exception_spec.rb +4 -4
- data/spec/grape/middleware/formatter_spec.rb +7 -4
- data/spec/grape/middleware/versioner/param_spec.rb +8 -7
- data/spec/grape/path_spec.rb +24 -14
- data/spec/grape/util/hash_stack_spec.rb +8 -8
- data/spec/grape/validations/coerce_spec.rb +75 -33
- data/spec/grape/validations/default_spec.rb +57 -0
- data/spec/grape/validations/presence_spec.rb +13 -11
- data/spec/grape/validations/values_spec.rb +76 -2
- data/spec/grape/validations_spec.rb +443 -20
- data/spec/spec_helper.rb +2 -2
- data/spec/support/content_type_helpers.rb +11 -0
- metadata +9 -38
@@ -1,9 +1,7 @@
|
|
1
1
|
module Grape
|
2
2
|
module ErrorFormatter
|
3
3
|
module Base
|
4
|
-
|
5
4
|
class << self
|
6
|
-
|
7
5
|
FORMATTERS = {
|
8
6
|
serializable_hash: Grape::ErrorFormatter::Json,
|
9
7
|
json: Grape::ErrorFormatter::Json,
|
@@ -27,7 +25,6 @@ module Grape
|
|
27
25
|
spec
|
28
26
|
end
|
29
27
|
end
|
30
|
-
|
31
28
|
end
|
32
29
|
end
|
33
30
|
end
|
@@ -2,7 +2,6 @@ module Grape
|
|
2
2
|
module ErrorFormatter
|
3
3
|
module Json
|
4
4
|
class << self
|
5
|
-
|
6
5
|
def call(message, backtrace, options = {}, env = nil)
|
7
6
|
result = message.is_a?(Hash) ? message : { error: message }
|
8
7
|
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
@@ -10,7 +9,6 @@ module Grape
|
|
10
9
|
end
|
11
10
|
MultiJson.dump(result)
|
12
11
|
end
|
13
|
-
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -2,7 +2,6 @@ module Grape
|
|
2
2
|
module ErrorFormatter
|
3
3
|
module Txt
|
4
4
|
class << self
|
5
|
-
|
6
5
|
def call(message, backtrace, options = {}, env = nil)
|
7
6
|
result = message.is_a?(Hash) ? MultiJson.dump(message) : message
|
8
7
|
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
@@ -11,7 +10,6 @@ module Grape
|
|
11
10
|
end
|
12
11
|
result
|
13
12
|
end
|
14
|
-
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -2,7 +2,6 @@ module Grape
|
|
2
2
|
module ErrorFormatter
|
3
3
|
module Xml
|
4
4
|
class << self
|
5
|
-
|
6
5
|
def call(message, backtrace, options = {}, env = nil)
|
7
6
|
result = message.is_a?(Hash) ? message : { message: message }
|
8
7
|
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
@@ -10,7 +9,6 @@ module Grape
|
|
10
9
|
end
|
11
10
|
result.respond_to?(:to_xml) ? result.to_xml(root: :error) : result.to_s
|
12
11
|
end
|
13
|
-
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Grape
|
2
2
|
module Exceptions
|
3
3
|
class Base < StandardError
|
4
|
-
|
5
4
|
BASE_MESSAGES_KEY = 'grape.errors.messages'
|
6
5
|
BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
|
7
6
|
FALLBACK_LOCALE = :en
|
@@ -62,7 +61,6 @@ module Grape
|
|
62
61
|
message = ::I18n.translate(key, options)
|
63
62
|
message.present? ? message : ::I18n.translate(key, options.merge(locale: FALLBACK_LOCALE))
|
64
63
|
end
|
65
|
-
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
@@ -2,12 +2,9 @@
|
|
2
2
|
module Grape
|
3
3
|
module Exceptions
|
4
4
|
class IncompatibleOptionValues < Base
|
5
|
-
|
6
5
|
def initialize(option1, value1, option2, value2)
|
7
6
|
super(message: compose_message("incompatible_option_values", option1: option1, value1: value1, option2: option2, value2: value2))
|
8
7
|
end
|
9
|
-
|
10
8
|
end
|
11
|
-
|
12
9
|
end
|
13
10
|
end
|
@@ -27,15 +27,16 @@ module Grape
|
|
27
27
|
private
|
28
28
|
|
29
29
|
def full_messages
|
30
|
-
map { |attribute, error| full_message(attribute, error) }
|
30
|
+
map { |attribute, error| full_message(attribute, error) }.uniq
|
31
31
|
end
|
32
32
|
|
33
33
|
def full_message(attribute, error)
|
34
|
-
I18n.t(
|
35
|
-
|
34
|
+
I18n.t(
|
35
|
+
"grape.errors.format".to_sym,
|
36
|
+
default: "%{attribute} %{message}",
|
36
37
|
attribute: translate_attribute(attribute),
|
37
|
-
message:
|
38
|
-
|
38
|
+
message: error.message
|
39
|
+
)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
data/lib/grape/formatter/base.rb
CHANGED
data/lib/grape/formatter/json.rb
CHANGED
@@ -2,7 +2,6 @@ module Grape
|
|
2
2
|
module Formatter
|
3
3
|
module SerializableHash
|
4
4
|
class << self
|
5
|
-
|
6
5
|
def call(object, env)
|
7
6
|
return object if object.is_a?(String)
|
8
7
|
return MultiJson.dump(serialize(object)) if serializable?(object)
|
@@ -12,24 +11,24 @@ module Grape
|
|
12
11
|
|
13
12
|
private
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
def serializable?(object)
|
15
|
+
object.respond_to?(:serializable_hash) || object.kind_of?(Array) && !object.map { |o| o.respond_to? :serializable_hash }.include?(false) || object.kind_of?(Hash)
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
else
|
30
|
-
object
|
18
|
+
def serialize(object)
|
19
|
+
if object.respond_to? :serializable_hash
|
20
|
+
object.serializable_hash
|
21
|
+
elsif object.kind_of?(Array) && !object.map { |o| o.respond_to? :serializable_hash }.include?(false)
|
22
|
+
object.map { |o| o.serializable_hash }
|
23
|
+
elsif object.kind_of?(Hash)
|
24
|
+
object.inject({}) do |h, (k, v)|
|
25
|
+
h[k] = serialize(v)
|
26
|
+
h
|
31
27
|
end
|
28
|
+
else
|
29
|
+
object
|
32
30
|
end
|
31
|
+
end
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
data/lib/grape/formatter/txt.rb
CHANGED
data/lib/grape/formatter/xml.rb
CHANGED
data/lib/grape/http/request.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
module Grape
|
2
2
|
class Request < Rack::Request
|
3
|
-
|
4
3
|
def params
|
5
|
-
@
|
4
|
+
@params ||= begin
|
6
5
|
params = Hashie::Mash.new(super)
|
7
6
|
if env['rack.routing_args']
|
8
7
|
args = env['rack.routing_args'].dup
|
@@ -15,7 +14,7 @@ module Grape
|
|
15
14
|
end
|
16
15
|
|
17
16
|
def headers
|
18
|
-
@
|
17
|
+
@headers ||= env.dup.inject({}) do |h, (k, v)|
|
19
18
|
if k.to_s.start_with? 'HTTP_'
|
20
19
|
k = k[5..-1].gsub('_', '-').downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
|
21
20
|
h[k] = v
|
@@ -23,6 +22,5 @@ module Grape
|
|
23
22
|
h
|
24
23
|
end
|
25
24
|
end
|
26
|
-
|
27
25
|
end
|
28
26
|
end
|
data/lib/grape/locale/en.yml
CHANGED
@@ -14,7 +14,7 @@ en:
|
|
14
14
|
missing_mime_type:
|
15
15
|
problem: 'missing mime type for %{new_format}'
|
16
16
|
resolution:
|
17
|
-
"you can choose
|
17
|
+
"you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES
|
18
18
|
or add your own with content_type :%{new_format}, 'application/%{new_format}'
|
19
19
|
"
|
20
20
|
invalid_with_option_for_represent:
|
@@ -5,9 +5,10 @@ module Grape::Middleware::Auth
|
|
5
5
|
{
|
6
6
|
token_class: 'AccessToken',
|
7
7
|
realm: 'OAuth API',
|
8
|
-
parameter: %w(bearer_token oauth_token),
|
8
|
+
parameter: %w(bearer_token oauth_token access_token),
|
9
9
|
accepted_headers: %w(HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION),
|
10
|
-
header: [/Bearer (.*)/i, /OAuth (.*)/i]
|
10
|
+
header: [/Bearer (.*)/i, /OAuth (.*)/i],
|
11
|
+
required: true
|
11
12
|
}
|
12
13
|
end
|
13
14
|
|
@@ -15,9 +16,17 @@ module Grape::Middleware::Auth
|
|
15
16
|
verify_token(token_parameter || token_header)
|
16
17
|
end
|
17
18
|
|
19
|
+
def request
|
20
|
+
@request ||= Grape::Request.new(env)
|
21
|
+
end
|
22
|
+
|
23
|
+
def params
|
24
|
+
@params ||= request.params
|
25
|
+
end
|
26
|
+
|
18
27
|
def token_parameter
|
19
28
|
Array(options[:parameter]).each do |p|
|
20
|
-
return
|
29
|
+
return params[p] if params[p]
|
21
30
|
end
|
22
31
|
nil
|
23
32
|
end
|
@@ -45,7 +54,7 @@ module Grape::Middleware::Auth
|
|
45
54
|
token = token_class.verify(token)
|
46
55
|
if token
|
47
56
|
if token.respond_to?(:expired?) && token.expired?
|
48
|
-
error_out(401, '
|
57
|
+
error_out(401, 'invalid_grant')
|
49
58
|
else
|
50
59
|
if !token.respond_to?(:permission_for?) || token.permission_for?(env)
|
51
60
|
env['api.token'] = token
|
@@ -53,8 +62,8 @@ module Grape::Middleware::Auth
|
|
53
62
|
error_out(403, 'insufficient_scope')
|
54
63
|
end
|
55
64
|
end
|
56
|
-
|
57
|
-
error_out(401, '
|
65
|
+
elsif !!options[:required]
|
66
|
+
error_out(401, 'invalid_grant')
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
@@ -27,14 +27,13 @@ module Grape
|
|
27
27
|
|
28
28
|
# @abstract
|
29
29
|
# Called before the application is called in the middleware lifecycle.
|
30
|
-
def before
|
30
|
+
def before
|
31
|
+
end
|
32
|
+
|
31
33
|
# @abstract
|
32
34
|
# Called after the application is called in the middleware lifecycle.
|
33
35
|
# @return [Response, nil] a Rack SPEC response or nil to call the application afterwards.
|
34
|
-
def after
|
35
|
-
|
36
|
-
def request
|
37
|
-
Grape::Request.new(env)
|
36
|
+
def after
|
38
37
|
end
|
39
38
|
|
40
39
|
def response
|
@@ -54,9 +53,10 @@ module Grape
|
|
54
53
|
end
|
55
54
|
|
56
55
|
def mime_types
|
57
|
-
content_types.
|
56
|
+
content_types.each_with_object({}) { |(k, v), types_without_params|
|
57
|
+
types_without_params[k] = v.split(';').first
|
58
|
+
}.invert
|
58
59
|
end
|
59
|
-
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|