grape 0.3.0 → 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 +15 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +70 -0
- data/.travis.yml +7 -6
- data/CHANGELOG.md +134 -4
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +5 -2
- data/README.md +551 -116
- data/RELEASING.md +105 -0
- data/Rakefile +29 -8
- data/UPGRADING.md +124 -0
- data/grape.gemspec +3 -3
- data/lib/grape/api.rb +207 -88
- data/lib/grape/cookies.rb +4 -8
- data/lib/grape/endpoint.rb +198 -144
- data/lib/grape/error_formatter/base.rb +5 -7
- data/lib/grape/error_formatter/json.rb +3 -5
- data/lib/grape/error_formatter/txt.rb +1 -3
- data/lib/grape/error_formatter/xml.rb +4 -6
- data/lib/grape/exceptions/base.rb +9 -9
- data/lib/grape/exceptions/incompatible_option_values.rb +10 -0
- data/lib/grape/exceptions/invalid_formatter.rb +1 -4
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -5
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -6
- data/lib/grape/exceptions/missing_mime_type.rb +1 -5
- data/lib/grape/exceptions/missing_option.rb +1 -4
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -4
- data/lib/grape/exceptions/unknown_options.rb +1 -5
- data/lib/grape/exceptions/unknown_validator.rb +1 -3
- data/lib/grape/exceptions/validation.rb +13 -3
- data/lib/grape/exceptions/validation_errors.rb +43 -0
- data/lib/grape/formatter/base.rb +5 -7
- data/lib/grape/formatter/json.rb +0 -3
- data/lib/grape/formatter/serializable_hash.rb +15 -15
- data/lib/grape/formatter/txt.rb +0 -2
- data/lib/grape/formatter/xml.rb +0 -2
- data/lib/grape/http/request.rb +26 -0
- data/lib/grape/locale/en.yml +8 -5
- data/lib/grape/middleware/auth/base.rb +30 -0
- data/lib/grape/middleware/auth/basic.rb +3 -20
- data/lib/grape/middleware/auth/digest.rb +2 -19
- data/lib/grape/middleware/auth/oauth2.rb +31 -24
- data/lib/grape/middleware/base.rb +7 -7
- data/lib/grape/middleware/error.rb +36 -22
- data/lib/grape/middleware/filter.rb +3 -3
- data/lib/grape/middleware/formatter.rb +99 -61
- data/lib/grape/middleware/globals.rb +13 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +67 -0
- data/lib/grape/middleware/versioner/header.rb +22 -16
- data/lib/grape/middleware/versioner/param.rb +9 -11
- data/lib/grape/middleware/versioner/path.rb +10 -13
- data/lib/grape/middleware/versioner.rb +3 -1
- data/lib/grape/namespace.rb +23 -0
- data/lib/grape/parser/base.rb +3 -5
- data/lib/grape/parser/json.rb +0 -2
- data/lib/grape/parser/xml.rb +0 -2
- data/lib/grape/path.rb +70 -0
- data/lib/grape/route.rb +10 -6
- data/lib/grape/util/content_types.rb +2 -1
- data/lib/grape/util/deep_merge.rb +5 -5
- data/lib/grape/util/hash_stack.rb +13 -2
- data/lib/grape/validations/coerce.rb +11 -10
- data/lib/grape/validations/default.rb +25 -0
- data/lib/grape/validations/presence.rb +7 -3
- data/lib/grape/validations/regexp.rb +2 -5
- data/lib/grape/validations/values.rb +17 -0
- data/lib/grape/validations.rb +161 -54
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +19 -4
- data/spec/grape/api_spec.rb +897 -268
- data/spec/grape/endpoint_spec.rb +283 -66
- data/spec/grape/entity_spec.rb +132 -29
- data/spec/grape/exceptions/missing_mime_type_spec.rb +3 -9
- data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
- data/spec/grape/middleware/auth/basic_spec.rb +8 -8
- data/spec/grape/middleware/auth/digest_spec.rb +5 -5
- data/spec/grape/middleware/auth/oauth2_spec.rb +81 -36
- data/spec/grape/middleware/base_spec.rb +8 -13
- data/spec/grape/middleware/error_spec.rb +13 -17
- data/spec/grape/middleware/exception_spec.rb +47 -27
- data/spec/grape/middleware/formatter_spec.rb +103 -41
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +121 -0
- data/spec/grape/middleware/versioner/header_spec.rb +76 -51
- data/spec/grape/middleware/versioner/param_spec.rb +18 -18
- data/spec/grape/middleware/versioner/path_spec.rb +6 -6
- data/spec/grape/middleware/versioner_spec.rb +5 -2
- data/spec/grape/path_spec.rb +229 -0
- data/spec/grape/util/hash_stack_spec.rb +31 -32
- data/spec/grape/validations/coerce_spec.rb +116 -51
- data/spec/grape/validations/default_spec.rb +123 -0
- data/spec/grape/validations/presence_spec.rb +42 -44
- data/spec/grape/validations/regexp_spec.rb +9 -9
- data/spec/grape/validations/values_spec.rb +138 -0
- data/spec/grape/validations/zh-CN.yml +4 -3
- data/spec/grape/validations_spec.rb +681 -48
- data/spec/shared/versioning_examples.rb +22 -6
- data/spec/spec_helper.rb +3 -2
- data/spec/support/basic_auth_encode_helpers.rb +0 -1
- data/spec/support/content_type_helpers.rb +11 -0
- data/spec/support/versioned_helpers.rb +13 -5
- metadata +34 -84
data/lib/grape/endpoint.rb
CHANGED
@@ -5,7 +5,7 @@ module Grape
|
|
5
5
|
# from inside a `get`, `post`, etc.
|
6
6
|
class Endpoint
|
7
7
|
attr_accessor :block, :source, :options, :settings
|
8
|
-
attr_reader :env, :request
|
8
|
+
attr_reader :env, :request, :headers, :params
|
9
9
|
|
10
10
|
class << self
|
11
11
|
# @api private
|
@@ -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
|
-
settings.gather(:namespace).join("/"),
|
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
|
-
|
54
|
+
def require_option(options, key)
|
55
|
+
raise Grape::Exceptions::MissingOption.new(key) unless options.has_key?(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
|
@@ -65,15 +72,15 @@ module Grape
|
|
65
72
|
endpoints.each { |e| e.mount_in(route_set) }
|
66
73
|
else
|
67
74
|
routes.each do |route|
|
68
|
-
methods = [
|
69
|
-
if !
|
75
|
+
methods = [route.route_method]
|
76
|
+
if !settings[:do_not_route_head] && route.route_method == "GET"
|
70
77
|
methods << "HEAD"
|
71
78
|
end
|
72
79
|
methods.each do |method|
|
73
80
|
route_set.add_route(self, {
|
74
|
-
:
|
75
|
-
:
|
76
|
-
},
|
81
|
+
path_info: route.route_compiled,
|
82
|
+
request_method: method,
|
83
|
+
}, route_info: route)
|
77
84
|
end
|
78
85
|
end
|
79
86
|
end
|
@@ -88,27 +95,31 @@ module Grape
|
|
88
95
|
anchor = options[:route_options][:anchor]
|
89
96
|
anchor = anchor.nil? ? true : anchor
|
90
97
|
|
91
|
-
|
98
|
+
endpoint_requirements = options[:route_options][:requirements] || {}
|
99
|
+
all_requirements = (settings.gather(:namespace).map(&:requirements) << endpoint_requirements)
|
100
|
+
requirements = all_requirements.reduce({}) do |base_requirements, single_requirements|
|
101
|
+
base_requirements.merge!(single_requirements)
|
102
|
+
end
|
92
103
|
|
93
104
|
path = compile_path(prepared_path, anchor && !options[:app], requirements)
|
94
105
|
regex = Rack::Mount::RegexpWithNamedGroups.new(path)
|
95
106
|
path_params = {}
|
96
107
|
# named parameters in the api path
|
97
|
-
named_params = regex.named_captures.map { |nc| nc[0] } -
|
108
|
+
named_params = regex.named_captures.map { |nc| nc[0] } - %w{ version format }
|
98
109
|
named_params.each { |named_param| path_params[named_param] = "" }
|
99
110
|
# route parameters declared via desc or appended to the api declaration
|
100
111
|
route_params = (options[:route_options][:params] || {})
|
101
112
|
path_params.merge!(route_params)
|
102
113
|
request_method = (method.to_s.upcase unless method == :any)
|
103
|
-
routes << Route.new(options[:route_options].clone.merge(
|
104
|
-
:
|
105
|
-
:
|
106
|
-
:
|
107
|
-
:
|
108
|
-
:
|
109
|
-
:
|
110
|
-
:
|
111
|
-
|
114
|
+
routes << Route.new(options[:route_options].clone.merge(
|
115
|
+
prefix: settings[:root_prefix],
|
116
|
+
version: settings[:version] ? settings[:version].join('|') : nil,
|
117
|
+
namespace: namespace,
|
118
|
+
method: request_method,
|
119
|
+
path: prepared_path,
|
120
|
+
params: path_params,
|
121
|
+
compiled: path,
|
122
|
+
)
|
112
123
|
)
|
113
124
|
end
|
114
125
|
end
|
@@ -116,28 +127,11 @@ module Grape
|
|
116
127
|
end
|
117
128
|
|
118
129
|
def prepare_path(path)
|
119
|
-
|
120
|
-
parts << settings[:mount_path].to_s.split("/") if settings[:mount_path]
|
121
|
-
parts << settings[:root_prefix].to_s.split("/") if settings[:root_prefix]
|
122
|
-
|
123
|
-
uses_path_versioning = settings[:version] && settings[:version_options][:using] == :path
|
124
|
-
namespace_is_empty = namespace && (namespace.to_s =~ /^\s*$/ || namespace.to_s == '/')
|
125
|
-
path_is_empty = path && (path.to_s =~ /^\s*$/ || path.to_s == '/')
|
126
|
-
|
127
|
-
parts << ':version' if uses_path_versioning
|
128
|
-
if ! uses_path_versioning || (! namespace_is_empty || ! path_is_empty)
|
129
|
-
parts << namespace.to_s if namespace
|
130
|
-
parts << path.to_s if path
|
131
|
-
format_suffix = '(.:format)'
|
132
|
-
else
|
133
|
-
format_suffix = '(/.:format)'
|
134
|
-
end
|
135
|
-
parts = parts.flatten.select { |part| part != '/' }
|
136
|
-
Rack::Mount::Utils.normalize_path(parts.join('/') + format_suffix)
|
130
|
+
Path.prepare(path, namespace, settings)
|
137
131
|
end
|
138
132
|
|
139
133
|
def namespace
|
140
|
-
|
134
|
+
@namespace ||= Namespace.joined_space_path(settings)
|
141
135
|
end
|
142
136
|
|
143
137
|
def compile_path(prepared_path, anchor = true, requirements = {})
|
@@ -152,56 +146,76 @@ module Grape
|
|
152
146
|
end
|
153
147
|
|
154
148
|
def call!(env)
|
149
|
+
extend helpers
|
150
|
+
|
155
151
|
env['api.endpoint'] = self
|
156
152
|
if options[:app]
|
157
153
|
options[:app].call(env)
|
158
154
|
else
|
159
155
|
builder = build_middleware
|
160
|
-
builder.run options[:app] || lambda{|
|
156
|
+
builder.run options[:app] || lambda { |arg| run(arg) }
|
161
157
|
builder.call(env)
|
162
158
|
end
|
163
159
|
end
|
164
160
|
|
165
|
-
# The parameters passed into the request as
|
166
|
-
# well as parsed from URL segments.
|
167
|
-
def params
|
168
|
-
@params ||= Hashie::Mash.new.
|
169
|
-
deep_merge(request.params).
|
170
|
-
deep_merge(env['rack.routing_args'] || {})
|
171
|
-
end
|
172
|
-
|
173
161
|
# A filtering method that will return a hash
|
174
162
|
# consisting only of keys that have been declared by a
|
175
|
-
# `params` statement
|
163
|
+
# `params` statement against the current/target endpoint or parent
|
164
|
+
# namespaces
|
176
165
|
#
|
177
166
|
# @param params [Hash] The initial hash to filter. Usually this will just be `params`
|
178
|
-
# @param options [Hash] Can pass `:include_missing` and `:
|
179
|
-
|
167
|
+
# @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces`
|
168
|
+
# options. `:include_parent_namespaces` defaults to true, hence must be set to false if
|
169
|
+
# you want only to return params declared against the current/target endpoint
|
170
|
+
def declared(params, options = {}, declared_params = nil)
|
180
171
|
options[:include_missing] = true unless options.key?(:include_missing)
|
172
|
+
options[:include_parent_namespaces] = true unless options.key?(:include_parent_namespaces)
|
173
|
+
if declared_params.nil?
|
174
|
+
declared_params = !options[:include_parent_namespaces] ? settings[:declared_params] :
|
175
|
+
settings.gather(:declared_params)
|
176
|
+
end
|
181
177
|
|
182
|
-
unless
|
178
|
+
unless declared_params
|
183
179
|
raise ArgumentError, "Tried to filter for declared parameters but none exist."
|
184
180
|
end
|
185
181
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
h[output_key] = params[k]
|
182
|
+
if params.is_a? Array
|
183
|
+
params.map do |param|
|
184
|
+
declared(param || {}, options, declared_params)
|
190
185
|
end
|
191
|
-
|
192
|
-
|
186
|
+
else
|
187
|
+
declared_params.inject({}) do |hash, key|
|
188
|
+
key = { key => nil } unless key.is_a? Hash
|
189
|
+
|
190
|
+
key.each_pair do |parent, children|
|
191
|
+
output_key = options[:stringify] ? parent.to_s : parent.to_sym
|
192
|
+
if params.key?(parent) || options[:include_missing]
|
193
|
+
hash[output_key] = if children
|
194
|
+
declared(params[parent] || {}, options, Array(children))
|
195
|
+
else
|
196
|
+
params[parent]
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
hash
|
202
|
+
end
|
203
|
+
end
|
193
204
|
end
|
194
205
|
|
195
206
|
# The API version as specified in the URL.
|
196
|
-
def version
|
207
|
+
def version
|
208
|
+
env['api.version']
|
209
|
+
end
|
197
210
|
|
198
211
|
# End the request and display an error to the
|
199
212
|
# end user with the specified message.
|
200
213
|
#
|
201
214
|
# @param message [String] The message to display.
|
202
|
-
# @param status [Integer] the HTTP Status Code. Defaults to
|
203
|
-
def error!(message, status=
|
204
|
-
|
215
|
+
# @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
|
216
|
+
def error!(message, status = nil, headers = nil)
|
217
|
+
status = settings[:default_error_status] unless status
|
218
|
+
throw :error, message: message, status: status, headers: headers
|
205
219
|
end
|
206
220
|
|
207
221
|
# Redirect to a new url.
|
@@ -210,7 +224,7 @@ module Grape
|
|
210
224
|
# @param options [Hash] The options used when redirect.
|
211
225
|
# :permanent, default true.
|
212
226
|
def redirect(url, options = {})
|
213
|
-
merged_options = {:
|
227
|
+
merged_options = { permanent: false }.merge(options)
|
214
228
|
if merged_options[:permanent]
|
215
229
|
status 301
|
216
230
|
else
|
@@ -233,10 +247,10 @@ module Grape
|
|
233
247
|
else
|
234
248
|
return @status if @status
|
235
249
|
case request.request_method.to_s.upcase
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
250
|
+
when 'POST'
|
251
|
+
201
|
252
|
+
else
|
253
|
+
200
|
240
254
|
end
|
241
255
|
end
|
242
256
|
end
|
@@ -251,17 +265,6 @@ module Grape
|
|
251
265
|
end
|
252
266
|
end
|
253
267
|
|
254
|
-
# Retrieves all available request headers.
|
255
|
-
def headers
|
256
|
-
@headers ||= @env.dup.inject({}) { |h, (k, v)|
|
257
|
-
if k.start_with? 'HTTP_'
|
258
|
-
k = k[5..-1].gsub('_', '-').downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
|
259
|
-
h[k] = v
|
260
|
-
end
|
261
|
-
h
|
262
|
-
}
|
263
|
-
end
|
264
|
-
|
265
268
|
# Set response content-type
|
266
269
|
def content_type(val)
|
267
270
|
header('Content-Type', val)
|
@@ -272,7 +275,7 @@ module Grape
|
|
272
275
|
# @example
|
273
276
|
# cookies[:mycookie] = 'mycookie val'
|
274
277
|
# cookies['mycookie-string'] = 'mycookie string val'
|
275
|
-
# cookies[:more] = { :
|
278
|
+
# cookies[:more] = { value: '123', expires: Time.at(0) }
|
276
279
|
# cookies.delete :more
|
277
280
|
#
|
278
281
|
def cookies
|
@@ -309,32 +312,41 @@ module Grape
|
|
309
312
|
#
|
310
313
|
# get '/users/:id' do
|
311
314
|
# present User.find(params[:id]),
|
312
|
-
# :
|
313
|
-
# :
|
315
|
+
# with: API::Entities::User,
|
316
|
+
# admin: current_user.admin?
|
314
317
|
# end
|
315
|
-
def present(
|
318
|
+
def present(*args)
|
319
|
+
options = args.count > 1 ? args.extract_options! : {}
|
320
|
+
key, object = if args.count == 2 && args.first.is_a?(Symbol)
|
321
|
+
args
|
322
|
+
else
|
323
|
+
[nil, args.first]
|
324
|
+
end
|
316
325
|
entity_class = options.delete(:with)
|
317
326
|
|
318
|
-
|
319
|
-
|
327
|
+
if entity_class.nil?
|
328
|
+
# entity class not explicitely defined, auto-detect from first object in the collection
|
329
|
+
object_instance = object.respond_to?(:first) ? object.first : object
|
320
330
|
|
321
|
-
|
322
|
-
|
323
|
-
|
331
|
+
object_instance.class.ancestors.each do |potential|
|
332
|
+
entity_class ||= (settings[:representations] || {})[potential]
|
333
|
+
end
|
324
334
|
|
325
|
-
|
335
|
+
entity_class ||= object_instance.class.const_get(:Entity) if object_instance.class.const_defined?(:Entity) && object_instance.class.const_get(:Entity).respond_to?(:represent)
|
336
|
+
end
|
326
337
|
|
327
338
|
root = options.delete(:root)
|
328
339
|
|
329
340
|
representation = if entity_class
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
341
|
+
embeds = { env: env }
|
342
|
+
embeds[:version] = env['api.version'] if env['api.version']
|
343
|
+
entity_class.represent(object, embeds.merge(options))
|
344
|
+
else
|
345
|
+
object
|
346
|
+
end
|
336
347
|
|
337
348
|
representation = { root => representation } if root
|
349
|
+
representation = (@body || {}).merge(key => representation) if key
|
338
350
|
body representation
|
339
351
|
end
|
340
352
|
|
@@ -350,8 +362,6 @@ module Grape
|
|
350
362
|
env["rack.routing_args"][:route_info]
|
351
363
|
end
|
352
364
|
|
353
|
-
protected
|
354
|
-
|
355
365
|
# Return the collection of endpoints within this endpoint.
|
356
366
|
# This is the case when an Grape::API mounts another Grape::API.
|
357
367
|
def endpoints
|
@@ -362,24 +372,39 @@ module Grape
|
|
362
372
|
end
|
363
373
|
end
|
364
374
|
|
375
|
+
protected
|
376
|
+
|
365
377
|
def run(env)
|
366
378
|
@env = env
|
367
379
|
@header = {}
|
368
|
-
@request = Rack::Request.new(@env)
|
369
380
|
|
370
|
-
|
381
|
+
@request = Grape::Request.new(env)
|
382
|
+
@params = @request.params
|
383
|
+
@headers = @request.headers
|
384
|
+
|
371
385
|
cookies.read(@request)
|
372
386
|
|
373
387
|
run_filters befores
|
374
388
|
|
389
|
+
run_filters before_validations
|
390
|
+
|
375
391
|
# Retieve validations from this namespace and all parent namespaces.
|
392
|
+
validation_errors = []
|
376
393
|
settings.gather(:validations).each do |validator|
|
377
|
-
|
394
|
+
begin
|
395
|
+
validator.validate!(params)
|
396
|
+
rescue Grape::Exceptions::Validation => e
|
397
|
+
validation_errors << e
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
if validation_errors.any?
|
402
|
+
raise Grape::Exceptions::ValidationErrors, errors: validation_errors
|
378
403
|
end
|
379
404
|
|
380
405
|
run_filters after_validations
|
381
406
|
|
382
|
-
response_text = @block.call(self)
|
407
|
+
response_text = @block ? @block.call(self) : nil
|
383
408
|
run_filters afters
|
384
409
|
cookies.write(header)
|
385
410
|
|
@@ -391,54 +416,71 @@ module Grape
|
|
391
416
|
|
392
417
|
b.use Rack::Head
|
393
418
|
b.use Grape::Middleware::Error,
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
b.use Rack::Auth::Digest::MD5, settings[:auth][:realm], settings[:auth][:opaque], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_digest
|
404
|
-
|
405
|
-
if settings[:version]
|
406
|
-
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]), {
|
407
|
-
:versions => settings[:version],
|
408
|
-
:version_options => settings[:version_options],
|
409
|
-
:prefix => settings[:root_prefix]
|
410
|
-
}
|
411
|
-
end
|
412
|
-
|
413
|
-
b.use Grape::Middleware::Formatter,
|
414
|
-
:format => settings[:format],
|
415
|
-
:default_format => settings[:default_format] || :txt,
|
416
|
-
:content_types => settings[:content_types],
|
417
|
-
:formatters => settings[:formatters],
|
418
|
-
:parsers => settings[:parsers]
|
419
|
+
format: settings[:format],
|
420
|
+
content_types: settings[:content_types],
|
421
|
+
default_status: settings[:default_error_status] || 500,
|
422
|
+
rescue_all: settings[:rescue_all],
|
423
|
+
default_error_formatter: settings[:default_error_formatter],
|
424
|
+
error_formatters: settings[:error_formatters],
|
425
|
+
rescue_options: settings[:rescue_options],
|
426
|
+
rescue_handlers: merged_setting(:rescue_handlers),
|
427
|
+
base_only_rescue_handlers: merged_setting(:base_only_rescue_handlers)
|
419
428
|
|
420
429
|
aggregate_setting(:middleware).each do |m|
|
421
430
|
m = m.dup
|
422
431
|
block = m.pop if m.last.is_a?(Proc)
|
423
432
|
if block
|
424
|
-
b.use
|
433
|
+
b.use(*m, &block)
|
425
434
|
else
|
426
|
-
b.use
|
435
|
+
b.use(*m)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
if settings[:auth]
|
440
|
+
auth_proc = settings[:auth][:proc]
|
441
|
+
auth_proc_context = self
|
442
|
+
auth_middleware = {
|
443
|
+
http_basic: { class: Rack::Auth::Basic, args: [settings[:auth][:realm]] },
|
444
|
+
http_digest: { class: Rack::Auth::Digest::MD5, args: [settings[:auth][:realm], settings[:auth][:opaque]] }
|
445
|
+
}[settings[:auth][:type]]
|
446
|
+
|
447
|
+
# evaluate auth proc in context of endpoint
|
448
|
+
if auth_middleware
|
449
|
+
b.use auth_middleware[:class], *auth_middleware[:args] do |*args|
|
450
|
+
auth_proc_context.instance_exec(*args, &auth_proc)
|
451
|
+
end
|
427
452
|
end
|
428
453
|
end
|
429
454
|
|
455
|
+
if settings[:version]
|
456
|
+
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]),
|
457
|
+
versions: settings[:version] ? settings[:version].flatten : nil,
|
458
|
+
version_options: settings[:version_options],
|
459
|
+
prefix: settings[:root_prefix]
|
460
|
+
|
461
|
+
end
|
462
|
+
|
463
|
+
b.use Grape::Middleware::Formatter,
|
464
|
+
format: settings[:format],
|
465
|
+
default_format: settings[:default_format] || :txt,
|
466
|
+
content_types: settings[:content_types],
|
467
|
+
formatters: settings[:formatters],
|
468
|
+
parsers: settings[:parsers]
|
469
|
+
|
430
470
|
b
|
431
471
|
end
|
432
472
|
|
433
473
|
def helpers
|
434
474
|
m = Module.new
|
435
|
-
settings.stack.each
|
475
|
+
settings.stack.each do |frame|
|
476
|
+
m.send :include, frame[:helpers] if frame[:helpers]
|
477
|
+
end
|
436
478
|
m
|
437
479
|
end
|
438
480
|
|
439
481
|
def aggregate_setting(key)
|
440
482
|
settings.stack.inject([]) do |aggregate, frame|
|
441
|
-
aggregate
|
483
|
+
aggregate + (frame[key] || [])
|
442
484
|
end
|
443
485
|
end
|
444
486
|
|
@@ -450,12 +492,24 @@ module Grape
|
|
450
492
|
|
451
493
|
def run_filters(filters)
|
452
494
|
(filters || []).each do |filter|
|
453
|
-
instance_eval
|
495
|
+
instance_eval(&filter)
|
454
496
|
end
|
455
497
|
end
|
456
498
|
|
457
|
-
def befores
|
458
|
-
|
459
|
-
|
499
|
+
def befores
|
500
|
+
aggregate_setting(:befores)
|
501
|
+
end
|
502
|
+
|
503
|
+
def before_validations
|
504
|
+
aggregate_setting(:before_validations)
|
505
|
+
end
|
506
|
+
|
507
|
+
def after_validations
|
508
|
+
aggregate_setting(:after_validations)
|
509
|
+
end
|
510
|
+
|
511
|
+
def afters
|
512
|
+
aggregate_setting(:afters)
|
513
|
+
end
|
460
514
|
end
|
461
515
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Grape
|
2
2
|
module ErrorFormatter
|
3
3
|
module Base
|
4
|
-
|
5
4
|
class << self
|
6
|
-
|
7
5
|
FORMATTERS = {
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
6
|
+
serializable_hash: Grape::ErrorFormatter::Json,
|
7
|
+
json: Grape::ErrorFormatter::Json,
|
8
|
+
jsonapi: Grape::ErrorFormatter::Json,
|
9
|
+
txt: Grape::ErrorFormatter::Txt,
|
10
|
+
xml: Grape::ErrorFormatter::Xml
|
12
11
|
}
|
13
12
|
|
14
13
|
def formatters(options)
|
@@ -26,7 +25,6 @@ module Grape
|
|
26
25
|
spec
|
27
26
|
end
|
28
27
|
end
|
29
|
-
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -2,15 +2,13 @@ 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
|
-
result = message.is_a?(Hash) ? message : { :
|
8
|
-
if (options[:rescue_options] || {})[:backtrace] && backtrace && !
|
9
|
-
result = result.merge(
|
6
|
+
result = message.is_a?(Hash) ? message : { error: message }
|
7
|
+
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
8
|
+
result = result.merge(backtrace: backtrace)
|
10
9
|
end
|
11
10
|
MultiJson.dump(result)
|
12
11
|
end
|
13
|
-
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -2,16 +2,14 @@ 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
|
-
if (options[:rescue_options] || {})[:backtrace] && backtrace && !
|
7
|
+
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
9
8
|
result += "\r\n "
|
10
9
|
result += backtrace.join("\r\n ")
|
11
10
|
end
|
12
11
|
result
|
13
12
|
end
|
14
|
-
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -2,15 +2,13 @@ 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
|
-
result = message.is_a?(Hash) ? message : { :
|
8
|
-
if (options[:rescue_options] || {})[:backtrace] && backtrace && !
|
9
|
-
result = result.merge(
|
6
|
+
result = message.is_a?(Hash) ? message : { message: message }
|
7
|
+
if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
|
8
|
+
result = result.merge(backtrace: backtrace)
|
10
9
|
end
|
11
|
-
result.respond_to?(:to_xml) ? result.to_xml(:
|
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
|