grape 2.4.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/CONTRIBUTING.md +1 -9
- data/README.md +72 -31
- data/UPGRADING.md +34 -0
- data/grape.gemspec +4 -4
- data/lib/grape/api/instance.rb +49 -72
- data/lib/grape/api.rb +24 -34
- data/lib/grape/dry_types.rb +48 -4
- data/lib/grape/dsl/callbacks.rb +8 -58
- data/lib/grape/dsl/desc.rb +8 -67
- data/lib/grape/dsl/helpers.rb +59 -64
- data/lib/grape/dsl/inside_route.rb +20 -43
- data/lib/grape/dsl/logger.rb +3 -6
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +7 -16
- data/lib/grape/dsl/request_response.rb +136 -139
- data/lib/grape/dsl/routing.rb +229 -201
- data/lib/grape/dsl/settings.rb +22 -134
- data/lib/grape/dsl/validations.rb +37 -45
- data/lib/grape/endpoint.rb +64 -96
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/exceptions/base.rb +1 -1
- data/lib/grape/exceptions/missing_group_type.rb +0 -2
- data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
- data/lib/grape/middleware/auth/dsl.rb +5 -6
- data/lib/grape/middleware/error.rb +1 -11
- data/lib/grape/middleware/formatter.rb +4 -2
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
- data/lib/grape/middleware/versioner/base.rb +24 -42
- data/lib/grape/middleware/versioner/header.rb +1 -1
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +11 -0
- data/lib/grape/params_builder/base.rb +2 -0
- data/lib/grape/router.rb +4 -3
- data/lib/grape/util/api_description.rb +56 -0
- data/lib/grape/util/base_inheritable.rb +5 -2
- data/lib/grape/util/inheritable_setting.rb +7 -0
- data/lib/grape/util/media_type.rb +1 -1
- data/lib/grape/util/registry.rb +1 -1
- data/lib/grape/validations/contract_scope.rb +2 -2
- data/lib/grape/validations/params_documentation.rb +50 -0
- data/lib/grape/validations/params_scope.rb +38 -53
- data/lib/grape/validations/types/array_coercer.rb +2 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -11
- data/lib/grape/validations/types/primitive_coercer.rb +1 -28
- data/lib/grape/validations/types.rb +10 -25
- data/lib/grape/validations/validators/base.rb +0 -7
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +7 -10
- metadata +24 -14
- data/lib/grape/api/helpers.rb +0 -9
- data/lib/grape/dsl/api.rb +0 -17
- data/lib/grape/dsl/configuration.rb +0 -15
- data/lib/grape/types/invalid_value.rb +0 -8
- data/lib/grape/util/strict_hash_configuration.rb +0 -108
- data/lib/grape/validations/attributes_doc.rb +0 -60
data/lib/grape/dry_types.rb
CHANGED
|
@@ -2,9 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DryTypes
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
# https://dry-rb.org/gems/dry-types/main/getting-started/
|
|
6
|
+
# limit to what Grape is using
|
|
7
|
+
include Dry.Types(:params, :coercible, :strict)
|
|
8
|
+
|
|
9
|
+
class StrictCache < Grape::Util::Cache
|
|
10
|
+
MAPPING = {
|
|
11
|
+
Grape::API::Boolean => DryTypes::Strict::Bool,
|
|
12
|
+
BigDecimal => DryTypes::Strict::Decimal,
|
|
13
|
+
Numeric => DryTypes::Strict::Integer | DryTypes::Strict::Float | DryTypes::Strict::Decimal,
|
|
14
|
+
TrueClass => DryTypes::Strict::Bool.constrained(eql: true),
|
|
15
|
+
FalseClass => DryTypes::Strict::Bool.constrained(eql: false)
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
@cache = Hash.new do |h, strict_type|
|
|
21
|
+
h[strict_type] = MAPPING.fetch(strict_type) do
|
|
22
|
+
DryTypes.wrapped_dry_types_const_get(DryTypes::Strict, strict_type)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ParamsCache < Grape::Util::Cache
|
|
29
|
+
MAPPING = {
|
|
30
|
+
Grape::API::Boolean => DryTypes::Params::Bool,
|
|
31
|
+
BigDecimal => DryTypes::Params::Decimal,
|
|
32
|
+
Numeric => DryTypes::Params::Integer | DryTypes::Params::Float | DryTypes::Params::Decimal,
|
|
33
|
+
TrueClass => DryTypes::Params::Bool.constrained(eql: true),
|
|
34
|
+
FalseClass => DryTypes::Params::Bool.constrained(eql: false),
|
|
35
|
+
String => DryTypes::Coercible::String
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
def initialize
|
|
39
|
+
super
|
|
40
|
+
@cache = Hash.new do |h, params_type|
|
|
41
|
+
h[params_type] = MAPPING.fetch(params_type) do
|
|
42
|
+
DryTypes.wrapped_dry_types_const_get(DryTypes::Params, params_type)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.wrapped_dry_types_const_get(dry_type, type)
|
|
49
|
+
dry_type.const_get(type.name, false)
|
|
50
|
+
rescue NameError
|
|
51
|
+
raise ArgumentError, "type #{type} should support coercion via `[]`" unless type.respond_to?(:[])
|
|
52
|
+
end
|
|
9
53
|
end
|
|
10
54
|
end
|
data/lib/grape/dsl/callbacks.rb
CHANGED
|
@@ -2,66 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
|
-
# Blocks can be executed before or after every API call, using `before`, `after`,
|
|
6
|
-
# `before_validation` and `after_validation`.
|
|
7
|
-
#
|
|
8
|
-
# Before and after callbacks execute in the following order:
|
|
9
|
-
#
|
|
10
|
-
# 1. `before`
|
|
11
|
-
# 2. `before_validation`
|
|
12
|
-
# 3. _validations_
|
|
13
|
-
# 4. `after_validation`
|
|
14
|
-
# 5. _the API call_
|
|
15
|
-
# 6. `after`
|
|
16
|
-
#
|
|
17
|
-
# Steps 4, 5 and 6 only happen if validation succeeds.
|
|
18
5
|
module Callbacks
|
|
19
|
-
|
|
6
|
+
# before: execute the given block before validation, coercion, or any endpoint
|
|
7
|
+
# before_validation: execute the given block after `before`, but prior to validation or coercion
|
|
8
|
+
# after_validation: execute the given block after validations and coercions, but before any endpoint code
|
|
9
|
+
# after: execute the given block after the endpoint code has run except in unsuccessful
|
|
10
|
+
# finally: execute the given block after the endpoint code even if unsuccessful
|
|
20
11
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Execute the given block before validation, coercion, or any endpoint
|
|
25
|
-
# code is executed.
|
|
26
|
-
def before(&block)
|
|
27
|
-
namespace_stackable(:befores, block)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Execute the given block after `before`, but prior to validation or
|
|
31
|
-
# coercion.
|
|
32
|
-
def before_validation(&block)
|
|
33
|
-
namespace_stackable(:before_validations, block)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Execute the given block after validations and coercions, but before
|
|
37
|
-
# any endpoint code.
|
|
38
|
-
def after_validation(&block)
|
|
39
|
-
namespace_stackable(:after_validations, block)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Execute the given block after the endpoint code has run.
|
|
43
|
-
def after(&block)
|
|
44
|
-
namespace_stackable(:afters, block)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Allows you to specify a something that will always be executed after a call
|
|
48
|
-
# API call. Unlike the `after` block, this code will run even on
|
|
49
|
-
# unsuccesful requests.
|
|
50
|
-
# @example
|
|
51
|
-
# class ExampleAPI < Grape::API
|
|
52
|
-
# before do
|
|
53
|
-
# ApiLogger.start
|
|
54
|
-
# end
|
|
55
|
-
# finally do
|
|
56
|
-
# ApiLogger.close
|
|
57
|
-
# end
|
|
58
|
-
# end
|
|
59
|
-
#
|
|
60
|
-
# This will make sure that the ApiLogger is opened and closed around every
|
|
61
|
-
# request
|
|
62
|
-
# @param ensured_block [Proc] The block to be executed after every api_call
|
|
63
|
-
def finally(&block)
|
|
64
|
-
namespace_stackable(:finallies, block)
|
|
12
|
+
%w[before before_validation after_validation after finally].each do |callback_method|
|
|
13
|
+
define_method callback_method.to_sym do |&block|
|
|
14
|
+
inheritable_setting.namespace_stackable[callback_method.pluralize.to_sym] = block
|
|
65
15
|
end
|
|
66
16
|
end
|
|
67
17
|
end
|
data/lib/grape/dsl/desc.rb
CHANGED
|
@@ -3,28 +3,7 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module Desc
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ROUTE_ATTRIBUTES = %i[
|
|
9
|
-
body_name
|
|
10
|
-
consumes
|
|
11
|
-
default
|
|
12
|
-
deprecated
|
|
13
|
-
description
|
|
14
|
-
detail
|
|
15
|
-
entity
|
|
16
|
-
headers
|
|
17
|
-
hidden
|
|
18
|
-
http_codes
|
|
19
|
-
is_array
|
|
20
|
-
named
|
|
21
|
-
nickname
|
|
22
|
-
params
|
|
23
|
-
produces
|
|
24
|
-
security
|
|
25
|
-
summary
|
|
26
|
-
tags
|
|
27
|
-
].freeze
|
|
6
|
+
extend Grape::DSL::Settings
|
|
28
7
|
|
|
29
8
|
# Add a description to the next namespace or function.
|
|
30
9
|
# @param description [String] descriptive string for this endpoint
|
|
@@ -70,54 +49,16 @@ module Grape
|
|
|
70
49
|
# # ...
|
|
71
50
|
# end
|
|
72
51
|
#
|
|
73
|
-
def desc(description, options =
|
|
74
|
-
|
|
52
|
+
def desc(description, options = {}, &config_block)
|
|
53
|
+
settings =
|
|
75
54
|
if config_block
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
description(description)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
config_class.configure(&config_block)
|
|
82
|
-
config_class.settings
|
|
83
|
-
end
|
|
55
|
+
endpoint_config = defined?(configuration) ? configuration : nil
|
|
56
|
+
Grape::Util::ApiDescription.new(description, endpoint_config, &config_block).settings
|
|
84
57
|
else
|
|
85
|
-
options
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
namespace_setting :description, opts
|
|
89
|
-
route_setting :description, opts
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Returns an object which configures itself via an instance-context DSL.
|
|
93
|
-
def desc_container(endpoint_configuration)
|
|
94
|
-
Module.new do
|
|
95
|
-
include Grape::Util::StrictHashConfiguration.module(*ROUTE_ATTRIBUTES)
|
|
96
|
-
config_context.define_singleton_method(:configuration) do
|
|
97
|
-
endpoint_configuration
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def config_context.success(*args)
|
|
101
|
-
entity(*args)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def config_context.failure(*args)
|
|
105
|
-
http_codes(*args)
|
|
58
|
+
options.merge(description: description)
|
|
106
59
|
end
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
private
|
|
111
|
-
|
|
112
|
-
def endpoint_configuration
|
|
113
|
-
return {} unless defined?(configuration)
|
|
114
|
-
|
|
115
|
-
if configuration.respond_to?(:evaluate)
|
|
116
|
-
configuration.evaluate
|
|
117
|
-
# Within `given` or `mounted blocks` the configuration is already evaluated
|
|
118
|
-
elsif configuration.is_a?(Hash)
|
|
119
|
-
configuration
|
|
120
|
-
end
|
|
60
|
+
inheritable_setting.namespace[:description] = settings
|
|
61
|
+
inheritable_setting.route[:description] = settings
|
|
121
62
|
end
|
|
122
63
|
end
|
|
123
64
|
end
|
data/lib/grape/dsl/helpers.rb
CHANGED
|
@@ -3,81 +3,76 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module Helpers
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
include_new_modules(new_modules)
|
|
37
|
-
include_block(block)
|
|
38
|
-
include_all_in_scope if !block && new_modules.empty?
|
|
39
|
-
end
|
|
6
|
+
# Add helper methods that will be accessible from any
|
|
7
|
+
# endpoint within this namespace (and child namespaces).
|
|
8
|
+
#
|
|
9
|
+
# When called without a block, all known helpers within this scope
|
|
10
|
+
# are included.
|
|
11
|
+
#
|
|
12
|
+
# @param [Array] new_modules optional array of modules to include
|
|
13
|
+
# @param [Block] block optional block of methods to include
|
|
14
|
+
#
|
|
15
|
+
# @example Define some helpers.
|
|
16
|
+
#
|
|
17
|
+
# class ExampleAPI < Grape::API
|
|
18
|
+
# helpers do
|
|
19
|
+
# def current_user
|
|
20
|
+
# User.find_by_id(params[:token])
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# @example Include many modules
|
|
26
|
+
#
|
|
27
|
+
# class ExampleAPI < Grape::API
|
|
28
|
+
# helpers Authentication, Mailer, OtherModule
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
def helpers(*new_modules, &block)
|
|
32
|
+
include_new_modules(new_modules)
|
|
33
|
+
include_block(block)
|
|
34
|
+
include_all_in_scope if !block && new_modules.empty?
|
|
35
|
+
end
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
private
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
def include_new_modules(modules)
|
|
40
|
+
return if modules.empty?
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
modules.each { |mod| make_inclusion(mod) }
|
|
43
|
+
end
|
|
48
44
|
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
def include_block(block)
|
|
46
|
+
return unless block
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
48
|
+
Module.new.tap do |mod|
|
|
49
|
+
make_inclusion(mod) { mod.class_eval(&block) }
|
|
55
50
|
end
|
|
51
|
+
end
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
def make_inclusion(mod, &block)
|
|
54
|
+
define_boolean_in_mod(mod)
|
|
55
|
+
inject_api_helpers_to_mod(mod, &block)
|
|
56
|
+
inheritable_setting.namespace_stackable[:helpers] = mod
|
|
57
|
+
end
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
end
|
|
59
|
+
def include_all_in_scope
|
|
60
|
+
Module.new.tap do |mod|
|
|
61
|
+
namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
|
|
62
|
+
change!
|
|
68
63
|
end
|
|
64
|
+
end
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
def define_boolean_in_mod(mod)
|
|
67
|
+
return if defined? mod::Boolean
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
mod.const_set(:Boolean, Grape::API::Boolean)
|
|
70
|
+
end
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
72
|
+
def inject_api_helpers_to_mod(mod, &block)
|
|
73
|
+
mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
|
|
74
|
+
yield if block
|
|
75
|
+
mod.api_changed(self)
|
|
81
76
|
end
|
|
82
77
|
|
|
83
78
|
# This module extends user defined helpers
|
|
@@ -100,7 +95,7 @@ module Grape
|
|
|
100
95
|
def process_named_params
|
|
101
96
|
return if @named_params.blank?
|
|
102
97
|
|
|
103
|
-
api.namespace_stackable
|
|
98
|
+
api.inheritable_setting.namespace_stackable[:named_params] = @named_params
|
|
104
99
|
end
|
|
105
100
|
end
|
|
106
101
|
end
|
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module InsideRoute
|
|
6
|
-
extend ActiveSupport::Concern
|
|
7
|
-
include Grape::DSL::Settings
|
|
8
|
-
include Grape::DSL::Headers
|
|
9
|
-
|
|
10
6
|
# Denotes a situation where a DSL method has been invoked in a
|
|
11
7
|
# filter which it should not yet be available in
|
|
12
8
|
class MethodNotYetAvailable < StandardError; end
|
|
@@ -35,7 +31,7 @@ module Grape
|
|
|
35
31
|
declared_hash(passed_params, options, declared_params, params_nested_path)
|
|
36
32
|
end
|
|
37
33
|
|
|
38
|
-
if (key_maps = namespace_stackable
|
|
34
|
+
if (key_maps = inheritable_setting.namespace_stackable[:contract_key_map])
|
|
39
35
|
key_maps.each { |key_map| key_map.write(passed_params, res) }
|
|
40
36
|
end
|
|
41
37
|
|
|
@@ -59,7 +55,7 @@ module Grape
|
|
|
59
55
|
end
|
|
60
56
|
|
|
61
57
|
def declared_hash_attr(passed_params, options, declared_param, params_nested_path, memo)
|
|
62
|
-
renamed_params =
|
|
58
|
+
renamed_params = inheritable_setting.route[:renamed_params] || {}
|
|
63
59
|
if declared_param.is_a?(Hash)
|
|
64
60
|
declared_param.each_pair do |declared_parent_param, declared_children_params|
|
|
65
61
|
params_nested_path_dup = params_nested_path.dup
|
|
@@ -123,10 +119,10 @@ module Grape
|
|
|
123
119
|
def optioned_declared_params(include_parent_namespaces)
|
|
124
120
|
declared_params = if include_parent_namespaces
|
|
125
121
|
# Declared params including parent namespaces
|
|
126
|
-
|
|
122
|
+
inheritable_setting.route[:declared_params]
|
|
127
123
|
else
|
|
128
124
|
# Declared params at current namespace
|
|
129
|
-
namespace_stackable
|
|
125
|
+
inheritable_setting.namespace_stackable[:declared_params].last || []
|
|
130
126
|
end
|
|
131
127
|
|
|
132
128
|
raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
|
|
@@ -168,7 +164,7 @@ module Grape
|
|
|
168
164
|
# @param backtrace [Array<String>] The backtrace of the exception that caused the error.
|
|
169
165
|
# @param original_exception [Exception] The original exception that caused the error.
|
|
170
166
|
def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
|
|
171
|
-
status = self.status(status || namespace_inheritable
|
|
167
|
+
status = self.status(status || inheritable_setting.namespace_inheritable[:default_error_status])
|
|
172
168
|
headers = additional_headers.present? ? header.merge(additional_headers) : header
|
|
173
169
|
throw :error,
|
|
174
170
|
message: message,
|
|
@@ -178,24 +174,6 @@ module Grape
|
|
|
178
174
|
original_exception: original_exception
|
|
179
175
|
end
|
|
180
176
|
|
|
181
|
-
# Creates a Rack response based on the provided message, status, and headers.
|
|
182
|
-
# The content type in the headers is set to the default content type unless provided.
|
|
183
|
-
# The message is HTML-escaped if the content type is 'text/html'.
|
|
184
|
-
#
|
|
185
|
-
# @param message [String] The content of the response.
|
|
186
|
-
# @param status [Integer] The HTTP status code.
|
|
187
|
-
# @params headers [Hash] (optional) Headers for the response
|
|
188
|
-
# (default: {Rack::CONTENT_TYPE => content_type}).
|
|
189
|
-
#
|
|
190
|
-
# Returns:
|
|
191
|
-
# A Rack::Response object containing the specified message, status, and headers.
|
|
192
|
-
#
|
|
193
|
-
def rack_response(message, status = 200, headers = { Rack::CONTENT_TYPE => content_type })
|
|
194
|
-
Grape.deprecator.warn('The rack_response method has been deprecated, use error! instead.')
|
|
195
|
-
message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
|
|
196
|
-
Rack::Response.new(Array.wrap(message), Rack::Utils.status_code(status), headers)
|
|
197
|
-
end
|
|
198
|
-
|
|
199
177
|
# Redirect to a new url.
|
|
200
178
|
#
|
|
201
179
|
# @param url [String] The url to be redirect.
|
|
@@ -359,8 +337,7 @@ module Grape
|
|
|
359
337
|
# with: API::Entities::User,
|
|
360
338
|
# admin: current_user.admin?
|
|
361
339
|
# end
|
|
362
|
-
def present(*args)
|
|
363
|
-
options = args.count > 1 ? args.extract_options! : {}
|
|
340
|
+
def present(*args, **options)
|
|
364
341
|
key, object = if args.count == 2 && args.first.is_a?(Symbol)
|
|
365
342
|
args
|
|
366
343
|
else
|
|
@@ -411,22 +388,22 @@ module Grape
|
|
|
411
388
|
# @return [Class] the located Entity class, or nil if none is found
|
|
412
389
|
def entity_class_for_obj(object, options)
|
|
413
390
|
entity_class = options.delete(:with)
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
entity_class ||= object_class.const_get(:Entity) if object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
|
|
391
|
+
return entity_class if entity_class
|
|
392
|
+
|
|
393
|
+
# entity class not explicitly defined, auto-detect from relation#klass or first object in the collection
|
|
394
|
+
object_class = if object.respond_to?(:klass)
|
|
395
|
+
object.klass
|
|
396
|
+
else
|
|
397
|
+
object.respond_to?(:first) ? object.first.class : object.class
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
representations = inheritable_setting.namespace_stackable_with_hash(:representations)
|
|
401
|
+
if representations
|
|
402
|
+
potential = object_class.ancestors.detect { |potential| representations.key?(potential) }
|
|
403
|
+
entity_class = representations[potential] if potential
|
|
428
404
|
end
|
|
429
405
|
|
|
406
|
+
entity_class = object_class.const_get(:Entity) if !entity_class && object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
|
|
430
407
|
entity_class
|
|
431
408
|
end
|
|
432
409
|
|
data/lib/grape/dsl/logger.rb
CHANGED
|
@@ -3,18 +3,15 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module Logger
|
|
6
|
-
include Grape::DSL::Settings
|
|
7
|
-
|
|
8
|
-
attr_writer :logger
|
|
9
|
-
|
|
10
6
|
# Set or retrive the configured logger. If none was configured, this
|
|
11
7
|
# method will create a new one, logging to stdout.
|
|
12
8
|
# @param logger [Object] the new logger to use
|
|
13
9
|
def logger(logger = nil)
|
|
10
|
+
global_settings = inheritable_setting.global
|
|
14
11
|
if logger
|
|
15
|
-
|
|
12
|
+
global_settings[:logger] = logger
|
|
16
13
|
else
|
|
17
|
-
|
|
14
|
+
global_settings[:logger] || global_settings[:logger] = ::Logger.new($stdout)
|
|
18
15
|
end
|
|
19
16
|
end
|
|
20
17
|
end
|
data/lib/grape/dsl/middleware.rb
CHANGED
|
@@ -3,51 +3,33 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module Middleware
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
arr = [:use, middleware_class, *args]
|
|
19
|
-
arr << block if block
|
|
20
|
-
|
|
21
|
-
namespace_stackable(:middleware, arr)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def insert(*args, &block)
|
|
25
|
-
arr = [:insert, *args]
|
|
26
|
-
arr << block if block
|
|
27
|
-
|
|
28
|
-
namespace_stackable(:middleware, arr)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def insert_before(*args, &block)
|
|
32
|
-
arr = [:insert_before, *args]
|
|
33
|
-
arr << block if block
|
|
34
|
-
|
|
35
|
-
namespace_stackable(:middleware, arr)
|
|
36
|
-
end
|
|
6
|
+
# Apply a custom middleware to the API. Applies
|
|
7
|
+
# to the current namespace and any children, but
|
|
8
|
+
# not parents.
|
|
9
|
+
#
|
|
10
|
+
# @param middleware_class [Class] The class of the middleware you'd like
|
|
11
|
+
# to inject.
|
|
12
|
+
def use(middleware_class, *args, &block)
|
|
13
|
+
arr = [:use, middleware_class, *args]
|
|
14
|
+
arr << block if block
|
|
15
|
+
|
|
16
|
+
inheritable_setting.namespace_stackable[:middleware] = arr
|
|
17
|
+
end
|
|
37
18
|
|
|
38
|
-
|
|
39
|
-
|
|
19
|
+
%i[insert insert_before insert_after].each do |method_name|
|
|
20
|
+
define_method method_name do |*args, &block|
|
|
21
|
+
arr = [method_name, *args]
|
|
40
22
|
arr << block if block
|
|
41
23
|
|
|
42
|
-
namespace_stackable
|
|
24
|
+
inheritable_setting.namespace_stackable[:middleware] = arr
|
|
43
25
|
end
|
|
26
|
+
end
|
|
44
27
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
28
|
+
# Retrieve an array of the middleware classes
|
|
29
|
+
# and arguments that are currently applied to the
|
|
30
|
+
# application.
|
|
31
|
+
def middleware
|
|
32
|
+
inheritable_setting.namespace_stackable[:middleware] || []
|
|
51
33
|
end
|
|
52
34
|
end
|
|
53
35
|
end
|
data/lib/grape/dsl/parameters.rb
CHANGED
|
@@ -6,8 +6,6 @@ module Grape
|
|
|
6
6
|
# and describe the parameters accepted by an endpoint, or all endpoints
|
|
7
7
|
# within a namespace.
|
|
8
8
|
module Parameters
|
|
9
|
-
extend ActiveSupport::Concern
|
|
10
|
-
|
|
11
9
|
# Set the module used to build the request.params.
|
|
12
10
|
#
|
|
13
11
|
# @param build_with the ParamBuilder module to use when building request.params
|
|
@@ -31,7 +29,7 @@ module Grape
|
|
|
31
29
|
# end
|
|
32
30
|
# end
|
|
33
31
|
def build_with(build_with)
|
|
34
|
-
@api.namespace_inheritable
|
|
32
|
+
@api.inheritable_setting.namespace_inheritable[:build_params_with] = build_with
|
|
35
33
|
end
|
|
36
34
|
|
|
37
35
|
# Include reusable params rules among current.
|
|
@@ -55,9 +53,8 @@ module Grape
|
|
|
55
53
|
# Collection.page(params[:page]).per(params[:per_page])
|
|
56
54
|
# end
|
|
57
55
|
# end
|
|
58
|
-
def use(*names)
|
|
59
|
-
named_params = @api.namespace_stackable_with_hash(:named_params) || {}
|
|
60
|
-
options = names.extract_options!
|
|
56
|
+
def use(*names, **options)
|
|
57
|
+
named_params = @api.inheritable_setting.namespace_stackable_with_hash(:named_params) || {}
|
|
61
58
|
names.each do |name|
|
|
62
59
|
params_block = named_params.fetch(name) do
|
|
63
60
|
raise "Params :#{name} not found!"
|
|
@@ -125,10 +122,7 @@ module Grape
|
|
|
125
122
|
# requires :name, type: String
|
|
126
123
|
# end
|
|
127
124
|
# end
|
|
128
|
-
def requires(*attrs, &block)
|
|
129
|
-
orig_attrs = attrs.clone
|
|
130
|
-
|
|
131
|
-
opts = attrs.extract_options!.clone
|
|
125
|
+
def requires(*attrs, **opts, &block)
|
|
132
126
|
opts[:presence] = { value: true, message: opts[:message] }
|
|
133
127
|
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
|
134
128
|
|
|
@@ -136,7 +130,7 @@ module Grape
|
|
|
136
130
|
require_required_and_optional_fields(attrs.first, opts)
|
|
137
131
|
else
|
|
138
132
|
validate_attributes(attrs, opts, &block)
|
|
139
|
-
block ? new_scope(
|
|
133
|
+
block ? new_scope(attrs, opts, &block) : push_declared_params(attrs, opts.slice(:as))
|
|
140
134
|
end
|
|
141
135
|
end
|
|
142
136
|
|
|
@@ -144,10 +138,7 @@ module Grape
|
|
|
144
138
|
# endpoint.
|
|
145
139
|
# @param (see #requires)
|
|
146
140
|
# @option (see #requires)
|
|
147
|
-
def optional(*attrs, &block)
|
|
148
|
-
orig_attrs = attrs.clone
|
|
149
|
-
|
|
150
|
-
opts = attrs.extract_options!.clone
|
|
141
|
+
def optional(*attrs, **opts, &block)
|
|
151
142
|
type = opts[:type]
|
|
152
143
|
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
|
153
144
|
|
|
@@ -162,7 +153,7 @@ module Grape
|
|
|
162
153
|
else
|
|
163
154
|
validate_attributes(attrs, opts, &block)
|
|
164
155
|
|
|
165
|
-
block ? new_scope(
|
|
156
|
+
block ? new_scope(attrs, opts, true, &block) : push_declared_params(attrs, opts.slice(:as))
|
|
166
157
|
end
|
|
167
158
|
end
|
|
168
159
|
|