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
|
@@ -3,168 +3,165 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module DSL
|
|
5
5
|
module RequestResponse
|
|
6
|
-
|
|
6
|
+
# Specify the default format for the API's serializers.
|
|
7
|
+
# May be `:json` or `:txt` (default).
|
|
8
|
+
def default_format(new_format = nil)
|
|
9
|
+
return inheritable_setting.namespace_inheritable[:default_format] if new_format.nil?
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
inheritable_setting.namespace_inheritable[:default_format] = new_format.to_sym
|
|
12
|
+
end
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
namespace_inheritable(:default_format, new_format.nil? ? nil : new_format.to_sym)
|
|
15
|
-
end
|
|
14
|
+
# Specify the format for the API's serializers.
|
|
15
|
+
# May be `:json`, `:xml`, `:txt`, etc.
|
|
16
|
+
def format(new_format = nil)
|
|
17
|
+
return inheritable_setting.namespace_inheritable[:format] if new_format.nil?
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return namespace_inheritable(:format) unless new_format
|
|
19
|
+
symbolic_new_format = new_format.to_sym
|
|
20
|
+
inheritable_setting.namespace_inheritable[:format] = symbolic_new_format
|
|
21
|
+
inheritable_setting.namespace_inheritable[:default_error_formatter] = Grape::ErrorFormatter.formatter_for(symbolic_new_format)
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
|
|
23
|
+
content_type = content_types[symbolic_new_format]
|
|
24
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
inheritable_setting.namespace_stackable[:content_types] = { symbolic_new_format => content_type }
|
|
27
|
+
end
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
# Specify a custom formatter for a content-type.
|
|
30
|
+
def formatter(content_type, new_formatter)
|
|
31
|
+
inheritable_setting.namespace_stackable[:formatters] = { content_type.to_sym => new_formatter }
|
|
32
|
+
end
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
# Specify a custom parser for a content-type.
|
|
35
|
+
def parser(content_type, new_parser)
|
|
36
|
+
inheritable_setting.namespace_stackable[:parsers] = { content_type.to_sym => new_parser }
|
|
37
|
+
end
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
end
|
|
39
|
+
# Specify a default error formatter.
|
|
40
|
+
def default_error_formatter(new_formatter_name = nil)
|
|
41
|
+
return inheritable_setting.namespace_inheritable[:default_error_formatter] if new_formatter_name.nil?
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
|
|
44
|
+
inheritable_setting.namespace_inheritable[:default_error_formatter] = new_formatter
|
|
45
|
+
end
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
def error_formatter(format, options)
|
|
48
|
+
formatter = if options.is_a?(Hash) && options.key?(:with)
|
|
49
|
+
options[:with]
|
|
50
|
+
else
|
|
51
|
+
options
|
|
52
|
+
end
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
options[:with]
|
|
53
|
-
else
|
|
54
|
-
options
|
|
55
|
-
end
|
|
54
|
+
inheritable_setting.namespace_stackable[:error_formatters] = { format.to_sym => formatter }
|
|
55
|
+
end
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
# Specify additional content-types, e.g.:
|
|
58
|
+
# content_type :xls, 'application/vnd.ms-excel'
|
|
59
|
+
def content_type(key, val)
|
|
60
|
+
inheritable_setting.namespace_stackable[:content_types] = { key.to_sym => val }
|
|
61
|
+
end
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
# All available content types.
|
|
64
|
+
def content_types
|
|
65
|
+
c_types = inheritable_setting.namespace_stackable_with_hash(:content_types)
|
|
66
|
+
Grape::ContentTypes.content_types_for c_types
|
|
67
|
+
end
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Grape::ContentTypes.content_types_for c_types
|
|
70
|
-
end
|
|
69
|
+
# Specify the default status code for errors.
|
|
70
|
+
def default_error_status(new_status = nil)
|
|
71
|
+
return inheritable_setting.namespace_inheritable[:default_error_status] if new_status.nil?
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
namespace_inheritable(:default_error_status, new_status)
|
|
75
|
-
end
|
|
73
|
+
inheritable_setting.namespace_inheritable[:default_error_status] = new_status
|
|
74
|
+
end
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
options = args.extract_options!
|
|
105
|
-
raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
|
|
106
|
-
|
|
107
|
-
handler ||= extract_with(options)
|
|
108
|
-
|
|
109
|
-
if args.include?(:all)
|
|
110
|
-
namespace_inheritable(:rescue_all, true)
|
|
111
|
-
namespace_inheritable(:all_rescue_handler, handler)
|
|
112
|
-
elsif args.include?(:grape_exceptions)
|
|
113
|
-
namespace_inheritable(:rescue_all, true)
|
|
114
|
-
namespace_inheritable(:rescue_grape_exceptions, true)
|
|
115
|
-
namespace_inheritable(:grape_exceptions_rescue_handler, handler)
|
|
116
|
-
else
|
|
117
|
-
handler_type =
|
|
118
|
-
case options[:rescue_subclasses]
|
|
119
|
-
when nil, true
|
|
120
|
-
:rescue_handlers
|
|
121
|
-
else
|
|
122
|
-
:base_only_rescue_handlers
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
namespace_reverse_stackable(handler_type, args.to_h { |arg| [arg, handler] })
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
namespace_stackable(:rescue_options, options)
|
|
76
|
+
# Allows you to rescue certain exceptions that occur to return
|
|
77
|
+
# a grape error rather than raising all the way to the
|
|
78
|
+
# server level.
|
|
79
|
+
#
|
|
80
|
+
# @example Rescue from custom exceptions
|
|
81
|
+
# class ExampleAPI < Grape::API
|
|
82
|
+
# class CustomError < StandardError; end
|
|
83
|
+
#
|
|
84
|
+
# rescue_from CustomError
|
|
85
|
+
# end
|
|
86
|
+
#
|
|
87
|
+
# @overload rescue_from(*exception_classes, **options)
|
|
88
|
+
# @param [Array] exception_classes A list of classes that you want to rescue, or
|
|
89
|
+
# the symbol :all to rescue from all exceptions.
|
|
90
|
+
# @param [Block] block Execution block to handle the given exception.
|
|
91
|
+
# @param [Hash] options Options for the rescue usage.
|
|
92
|
+
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
|
|
93
|
+
# @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
|
|
94
|
+
# @param [Proc] handler Execution proc to handle the given exception as an
|
|
95
|
+
# alternative to passing a block.
|
|
96
|
+
def rescue_from(*args, **options, &block)
|
|
97
|
+
if args.last.is_a?(Proc)
|
|
98
|
+
handler = args.pop
|
|
99
|
+
elsif block
|
|
100
|
+
handler = block
|
|
129
101
|
end
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
|
|
153
|
-
|
|
154
|
-
namespace_stackable(:representations, model_class => options[:with])
|
|
103
|
+
raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
|
|
104
|
+
|
|
105
|
+
handler ||= extract_with(options)
|
|
106
|
+
|
|
107
|
+
if args.include?(:all)
|
|
108
|
+
inheritable_setting.namespace_inheritable[:rescue_all] = true
|
|
109
|
+
inheritable_setting.namespace_inheritable[:all_rescue_handler] = handler
|
|
110
|
+
elsif args.include?(:grape_exceptions)
|
|
111
|
+
inheritable_setting.namespace_inheritable[:rescue_all] = true
|
|
112
|
+
inheritable_setting.namespace_inheritable[:rescue_grape_exceptions] = true
|
|
113
|
+
inheritable_setting.namespace_inheritable[:grape_exceptions_rescue_handler] = handler
|
|
114
|
+
else
|
|
115
|
+
handler_type =
|
|
116
|
+
case options[:rescue_subclasses]
|
|
117
|
+
when nil, true
|
|
118
|
+
:rescue_handlers
|
|
119
|
+
else
|
|
120
|
+
:base_only_rescue_handlers
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
inheritable_setting.namespace_reverse_stackable[handler_type] = args.to_h { |arg| [arg, handler] }
|
|
155
124
|
end
|
|
156
125
|
|
|
157
|
-
|
|
126
|
+
inheritable_setting.namespace_stackable[:rescue_options] = options
|
|
127
|
+
end
|
|
158
128
|
|
|
159
|
-
|
|
160
|
-
|
|
129
|
+
# Allows you to specify a default representation entity for a
|
|
130
|
+
# class. This allows you to map your models to their respective
|
|
131
|
+
# entities once and then simply call `present` with the model.
|
|
132
|
+
#
|
|
133
|
+
# @example
|
|
134
|
+
# class ExampleAPI < Grape::API
|
|
135
|
+
# represent User, with: Entity::User
|
|
136
|
+
#
|
|
137
|
+
# get '/me' do
|
|
138
|
+
# present current_user # with: Entity::User is assumed
|
|
139
|
+
# end
|
|
140
|
+
# end
|
|
141
|
+
#
|
|
142
|
+
# Note that Grape will automatically go up the class ancestry to
|
|
143
|
+
# try to find a representing entity, so if you, for example, define
|
|
144
|
+
# an entity to represent `Object` then all presented objects will
|
|
145
|
+
# bubble up and utilize the entity provided on that `represent` call.
|
|
146
|
+
#
|
|
147
|
+
# @param model_class [Class] The model class that will be represented.
|
|
148
|
+
# @option options [Class] :with The entity class that will represent the model.
|
|
149
|
+
def represent(model_class, options)
|
|
150
|
+
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
|
|
151
|
+
|
|
152
|
+
inheritable_setting.namespace_stackable[:representations] = { model_class => options[:with] }
|
|
153
|
+
end
|
|
161
154
|
|
|
162
|
-
|
|
163
|
-
return with_option if with_option.instance_of?(Proc)
|
|
164
|
-
return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
|
|
155
|
+
private
|
|
165
156
|
|
|
166
|
-
|
|
167
|
-
|
|
157
|
+
def extract_with(options)
|
|
158
|
+
return unless options.key?(:with)
|
|
159
|
+
|
|
160
|
+
with_option = options.delete(:with)
|
|
161
|
+
return with_option if with_option.instance_of?(Proc)
|
|
162
|
+
return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
|
|
163
|
+
|
|
164
|
+
raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
|
|
168
165
|
end
|
|
169
166
|
end
|
|
170
167
|
end
|