grape 2.3.0 → 2.4.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 +29 -0
- data/CONTRIBUTING.md +1 -1
- data/README.md +36 -14
- data/UPGRADING.md +56 -1
- data/grape.gemspec +1 -1
- data/lib/grape/api/instance.rb +3 -2
- data/lib/grape/api.rb +43 -66
- data/lib/grape/cookies.rb +31 -25
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/headers.rb +1 -1
- data/lib/grape/dsl/helpers.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +6 -18
- data/lib/grape/dsl/parameters.rb +3 -3
- data/lib/grape/dsl/routing.rb +9 -1
- data/lib/grape/endpoint.rb +30 -33
- data/lib/grape/exceptions/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
- data/lib/grape/extensions/hash.rb +2 -1
- data/lib/grape/extensions/hashie/mash.rb +3 -5
- data/lib/grape/locale/en.yml +44 -44
- data/lib/grape/middleware/auth/base.rb +11 -32
- data/lib/grape/middleware/auth/dsl.rb +23 -29
- data/lib/grape/middleware/base.rb +30 -11
- data/lib/grape/middleware/error.rb +16 -24
- data/lib/grape/middleware/formatter.rb +38 -72
- data/lib/grape/middleware/stack.rb +26 -36
- data/lib/grape/middleware/versioner/accept_version_header.rb +1 -3
- data/lib/grape/middleware/versioner/base.rb +10 -18
- data/lib/grape/middleware/versioner/header.rb +1 -1
- data/lib/grape/middleware/versioner/param.rb +2 -3
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/request.rb +161 -22
- data/lib/grape/router/route.rb +1 -1
- data/lib/grape/router.rb +25 -7
- data/lib/grape/validations/params_scope.rb +8 -3
- data/lib/grape/validations/validators/base.rb +2 -2
- data/lib/grape/validations/validators/except_values_validator.rb +1 -1
- data/lib/grape/validations/validators/presence_validator.rb +1 -1
- data/lib/grape/validations/validators/regexp_validator.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +13 -1
- metadata +18 -13
- data/lib/grape/error_formatter/jsonapi.rb +0 -7
- data/lib/grape/http/headers.rb +0 -56
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/parser/jsonapi.rb +0 -7
- data/lib/grape/util/lazy/object.rb +0 -45
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -23,14 +23,14 @@ module Grape
|
|
23
23
|
# class API < Grape::API
|
24
24
|
# desc "Get collection"
|
25
25
|
# params do
|
26
|
-
# build_with
|
26
|
+
# build_with :hashie_mash
|
27
27
|
# requires :user_id, type: Integer
|
28
28
|
# end
|
29
29
|
# get do
|
30
30
|
# params['user_id']
|
31
31
|
# end
|
32
32
|
# end
|
33
|
-
def build_with(build_with
|
33
|
+
def build_with(build_with)
|
34
34
|
@api.namespace_inheritable(:build_params_with, build_with)
|
35
35
|
end
|
36
36
|
|
@@ -251,7 +251,7 @@ module Grape
|
|
251
251
|
# @return hash of parameters relevant for the current scope
|
252
252
|
# @api private
|
253
253
|
def params(params)
|
254
|
-
params = @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
254
|
+
params = @parent.params_meeting_dependency.presence || @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
255
255
|
params = map_params(params, @element) if instance_variable_defined?(:@element) && @element
|
256
256
|
params
|
257
257
|
end
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -67,6 +67,10 @@ module Grape
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
def build_with(build_with)
|
71
|
+
namespace_inheritable(:build_params_with, build_with)
|
72
|
+
end
|
73
|
+
|
70
74
|
# Do not route HEAD requests to GET requests automatically.
|
71
75
|
def do_not_route_head!
|
72
76
|
namespace_inheritable(:do_not_route_head, true)
|
@@ -77,6 +81,10 @@ module Grape
|
|
77
81
|
namespace_inheritable(:do_not_route_options, true)
|
78
82
|
end
|
79
83
|
|
84
|
+
def lint!
|
85
|
+
namespace_inheritable(:lint, true)
|
86
|
+
end
|
87
|
+
|
80
88
|
def do_not_document!
|
81
89
|
namespace_inheritable(:do_not_document, true)
|
82
90
|
end
|
@@ -154,7 +162,7 @@ module Grape
|
|
154
162
|
reset_validations!
|
155
163
|
end
|
156
164
|
|
157
|
-
Grape::
|
165
|
+
Grape::HTTP_SUPPORTED_METHODS.each do |supported_method|
|
158
166
|
define_method supported_method.downcase do |*args, &block|
|
159
167
|
options = args.extract_options!
|
160
168
|
paths = args.first || ['/']
|
data/lib/grape/endpoint.rb
CHANGED
@@ -6,11 +6,15 @@ module Grape
|
|
6
6
|
# on the instance level of this class may be called
|
7
7
|
# from inside a `get`, `post`, etc.
|
8
8
|
class Endpoint
|
9
|
+
extend Forwardable
|
9
10
|
include Grape::DSL::Settings
|
10
11
|
include Grape::DSL::InsideRoute
|
11
12
|
|
12
13
|
attr_accessor :block, :source, :options
|
13
|
-
attr_reader :env, :request
|
14
|
+
attr_reader :env, :request
|
15
|
+
|
16
|
+
def_delegators :request, :params, :headers, :cookies
|
17
|
+
def_delegator :cookies, :response_cookies
|
14
18
|
|
15
19
|
class << self
|
16
20
|
def new(...)
|
@@ -30,7 +34,7 @@ module Grape
|
|
30
34
|
|
31
35
|
def run_before_each(endpoint)
|
32
36
|
superclass.run_before_each(endpoint) unless self == Endpoint
|
33
|
-
before_each.each { |blk| blk.
|
37
|
+
before_each.each { |blk| blk.try(:call, endpoint) }
|
34
38
|
end
|
35
39
|
|
36
40
|
# @api private
|
@@ -135,7 +139,7 @@ module Grape
|
|
135
139
|
end
|
136
140
|
|
137
141
|
def routes
|
138
|
-
@routes ||= endpoints
|
142
|
+
@routes ||= endpoints&.collect(&:routes)&.flatten || to_routes
|
139
143
|
end
|
140
144
|
|
141
145
|
def reset_routes!
|
@@ -161,10 +165,9 @@ module Grape
|
|
161
165
|
|
162
166
|
def to_routes
|
163
167
|
default_route_options = prepare_default_route_attributes
|
164
|
-
default_path_settings = prepare_default_path_settings
|
165
168
|
|
166
169
|
map_routes do |method, raw_path|
|
167
|
-
prepared_path = Path.new(raw_path, namespace,
|
170
|
+
prepared_path = Path.new(raw_path, namespace, prepare_default_path_settings)
|
168
171
|
params = options[:route_options].present? ? options[:route_options].merge(default_route_options) : default_route_options
|
169
172
|
route = Grape::Router::Route.new(method, prepared_path.origin, prepared_path.suffix, params)
|
170
173
|
route.apply(self)
|
@@ -225,7 +228,7 @@ module Grape
|
|
225
228
|
# Return the collection of endpoints within this endpoint.
|
226
229
|
# This is the case when an Grape::API mounts another Grape::API.
|
227
230
|
def endpoints
|
228
|
-
|
231
|
+
@endpoints ||= options[:app].try(:endpoints)
|
229
232
|
end
|
230
233
|
|
231
234
|
def equals?(endpoint)
|
@@ -245,20 +248,16 @@ module Grape
|
|
245
248
|
|
246
249
|
def run
|
247
250
|
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env: env) do
|
248
|
-
@header = Grape::Util::Header.new
|
249
251
|
@request = Grape::Request.new(env, build_params_with: namespace_inheritable(:build_params_with))
|
250
|
-
@params = @request.params
|
251
|
-
@headers = @request.headers
|
252
252
|
begin
|
253
|
-
cookies.read(@request)
|
254
253
|
self.class.run_before_each(self)
|
255
254
|
run_filters befores, :before
|
256
255
|
|
257
|
-
if (
|
258
|
-
|
259
|
-
raise Grape::Exceptions::MethodNotAllowed.new(header
|
256
|
+
if env.key?(Grape::Env::GRAPE_ALLOWED_METHODS)
|
257
|
+
header['Allow'] = env[Grape::Env::GRAPE_ALLOWED_METHODS].join(', ')
|
258
|
+
raise Grape::Exceptions::MethodNotAllowed.new(header) unless options?
|
260
259
|
|
261
|
-
header
|
260
|
+
header 'Allow', header['Allow']
|
262
261
|
response_object = ''
|
263
262
|
status 204
|
264
263
|
else
|
@@ -269,7 +268,7 @@ module Grape
|
|
269
268
|
end
|
270
269
|
|
271
270
|
run_filters afters, :after
|
272
|
-
|
271
|
+
build_response_cookies
|
273
272
|
|
274
273
|
# status verifies body presence when DELETE
|
275
274
|
@body ||= response_object
|
@@ -331,24 +330,10 @@ module Grape
|
|
331
330
|
extend post_extension if post_extension
|
332
331
|
end
|
333
332
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
def before_validations
|
339
|
-
namespace_stackable(:before_validations)
|
340
|
-
end
|
341
|
-
|
342
|
-
def after_validations
|
343
|
-
namespace_stackable(:after_validations)
|
344
|
-
end
|
345
|
-
|
346
|
-
def afters
|
347
|
-
namespace_stackable(:afters)
|
348
|
-
end
|
349
|
-
|
350
|
-
def finallies
|
351
|
-
namespace_stackable(:finallies)
|
333
|
+
%i[befores before_validations after_validations afters finallies].each do |method|
|
334
|
+
define_method method do
|
335
|
+
namespace_stackable(method)
|
336
|
+
end
|
352
337
|
end
|
353
338
|
|
354
339
|
def validations
|
@@ -373,6 +358,7 @@ module Grape
|
|
373
358
|
format = namespace_inheritable(:format)
|
374
359
|
|
375
360
|
stack.use Rack::Head
|
361
|
+
stack.use Rack::Lint if lint?
|
376
362
|
stack.use Class.new(Grape::Middleware::Error),
|
377
363
|
helpers: helpers,
|
378
364
|
format: format,
|
@@ -416,5 +402,16 @@ module Grape
|
|
416
402
|
|
417
403
|
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
|
418
404
|
end
|
405
|
+
|
406
|
+
def build_response_cookies
|
407
|
+
response_cookies do |name, value|
|
408
|
+
cookie_value = value.is_a?(Hash) ? value : { value: value }
|
409
|
+
Rack::Utils.set_cookie_header! header, name, cookie_value
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
def lint?
|
414
|
+
namespace_inheritable(:lint) || Grape.config.lint
|
415
|
+
end
|
419
416
|
end
|
420
417
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Exceptions
|
5
|
+
class UnknownParamsBuilder < Base
|
6
|
+
def initialize(params_builder_type)
|
7
|
+
super(message: compose_message(:unknown_params_builder, params_builder_type: params_builder_type))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -8,11 +8,8 @@ module Grape
|
|
8
8
|
extend ::ActiveSupport::Concern
|
9
9
|
|
10
10
|
included do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def params_builder
|
15
|
-
Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
|
11
|
+
Grape.deprecator.warn 'This concern has been deprecated. Use `build_with` with one of the following short_name (:hash, :hash_with_indifferent_access, :hashie_mash) instead.'
|
12
|
+
namespace_inheritable(:build_params_with, :hash_with_indifferent_access)
|
16
13
|
end
|
17
14
|
|
18
15
|
def build_params
|
@@ -7,7 +7,8 @@ module Grape
|
|
7
7
|
extend ::ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
|
10
|
+
Grape.deprecator.warn 'This concern has been deprecated. Use `build_with` with one of the following short_name (:hash, :hash_with_indifferent_access, :hashie_mash) instead.'
|
11
|
+
namespace_inheritable(:build_params_with, :hash)
|
11
12
|
end
|
12
13
|
|
13
14
|
def build_params
|
@@ -6,12 +6,10 @@ module Grape
|
|
6
6
|
module Mash
|
7
7
|
module ParamBuilder
|
8
8
|
extend ::ActiveSupport::Concern
|
9
|
-
included do
|
10
|
-
namespace_inheritable(:build_params_with, Grape::Extensions::Hashie::Mash::ParamBuilder)
|
11
|
-
end
|
12
9
|
|
13
|
-
|
14
|
-
Grape
|
10
|
+
included do
|
11
|
+
Grape.deprecator.warn 'This concern has been deprecated. Use `build_with` with one of the following short_name (:hash, :hash_with_indifferent_access, :hashie_mash) instead.'
|
12
|
+
namespace_inheritable(:build_params_with, :hashie_mash)
|
15
13
|
end
|
16
14
|
|
17
15
|
def build_params
|
data/lib/grape/locale/en.yml
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
+
---
|
1
2
|
en:
|
2
3
|
grape:
|
3
4
|
errors:
|
4
|
-
format:
|
5
|
+
format: '%{attributes} %{message}'
|
5
6
|
messages:
|
6
|
-
|
7
|
-
|
8
|
-
regexp: 'is invalid'
|
7
|
+
all_or_none: 'provide all or none of parameters'
|
8
|
+
at_least_one: 'are missing, at least one parameter must be provided'
|
9
9
|
blank: 'is empty'
|
10
|
-
|
10
|
+
coerce: 'is invalid'
|
11
|
+
conflicting_types: 'query params contains conflicting types'
|
12
|
+
empty_message_body: 'empty message body supplied with %{body_format} content-type'
|
13
|
+
exactly_one: 'are missing, exactly one parameter must be provided'
|
11
14
|
except_values: 'has a value not allowed'
|
12
|
-
|
15
|
+
incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
|
16
|
+
invalid_accept_header:
|
17
|
+
problem: 'invalid accept header'
|
18
|
+
resolution: '%{message}'
|
19
|
+
invalid_formatter: 'cannot convert %{klass} to %{to_format}'
|
20
|
+
invalid_message_body:
|
21
|
+
problem: 'message body does not match declared format'
|
22
|
+
resolution: 'when specifying %{body_format} as content-type, you must pass valid %{body_format} in the request''s ''body'' '
|
23
|
+
invalid_parameters: 'query params contains invalid format or byte sequence'
|
24
|
+
invalid_response: 'Invalid response'
|
25
|
+
invalid_version_header:
|
26
|
+
problem: 'invalid version header'
|
27
|
+
resolution: '%{message}'
|
28
|
+
invalid_versioner_option:
|
29
|
+
problem: 'unknown :using for versioner: %{strategy}'
|
30
|
+
resolution: 'available strategy for :using is :path, :header, :accept_version_header, :param'
|
31
|
+
invalid_with_option_for_represent:
|
32
|
+
problem: 'you must specify an entity class in the :with option'
|
33
|
+
resolution: 'eg: represent User, :with => Entity::User'
|
13
34
|
length: 'is expected to have length within %{min} and %{max}'
|
14
35
|
length_is: 'is expected to have length exactly equal to %{is}'
|
15
|
-
length_min: 'is expected to have length greater than or equal to %{min}'
|
16
36
|
length_max: 'is expected to have length less than or equal to %{max}'
|
17
|
-
|
18
|
-
|
19
|
-
summary: 'when version using header, you must specify :vendor option'
|
20
|
-
resolution: "eg: version 'v1', using: :header, vendor: 'twitter'"
|
37
|
+
length_min: 'is expected to have length greater than or equal to %{min}'
|
38
|
+
missing_group_type: 'group type is required'
|
21
39
|
missing_mime_type:
|
22
40
|
problem: 'missing mime type for %{new_format}'
|
23
|
-
resolution:
|
24
|
-
"you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES
|
25
|
-
or add your own with content_type :%{new_format}, 'application/%{new_format}'
|
26
|
-
"
|
27
|
-
invalid_with_option_for_represent:
|
28
|
-
problem: 'you must specify an entity class in the :with option'
|
29
|
-
resolution: 'eg: represent User, :with => Entity::User'
|
41
|
+
resolution: 'you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES or add your own with content_type :%{new_format}, ''application/%{new_format}'' '
|
30
42
|
missing_option: 'you must specify :%{option} options'
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
43
|
+
missing_vendor_option:
|
44
|
+
problem: 'missing :vendor option'
|
45
|
+
resolution: 'eg: version ''v1'', using: :header, vendor: ''twitter'''
|
46
|
+
summary: 'when version using header, you must specify :vendor option'
|
47
|
+
mutual_exclusion: 'are mutually exclusive'
|
48
|
+
presence: 'is missing'
|
49
|
+
regexp: 'is invalid'
|
50
|
+
same_as: 'is not the same as %{parameter}'
|
51
|
+
too_deep_parameters: 'query params are recursively nested over the specified limit (%{limit})'
|
52
|
+
too_many_multipart_files: 'the number of uploaded files exceeded the system''s configured limit (%{limit})'
|
53
|
+
unknown_auth_strategy: 'unknown auth strategy: %{strategy}'
|
36
54
|
unknown_options: 'unknown options: %{options}'
|
37
55
|
unknown_parameter: 'unknown parameter: %{param}'
|
38
|
-
|
39
|
-
|
40
|
-
at_least_one: 'are missing, at least one parameter must be provided'
|
41
|
-
exactly_one: 'are missing, exactly one parameter must be provided'
|
42
|
-
all_or_none: 'provide all or none of parameters'
|
43
|
-
missing_group_type: 'group type is required'
|
56
|
+
unknown_params_builder: 'unknown params_builder: %{params_builder_type}'
|
57
|
+
unknown_validator: 'unknown validator: %{validator_type}'
|
44
58
|
unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
|
45
|
-
|
46
|
-
problem: "message body does not match declared format"
|
47
|
-
resolution:
|
48
|
-
"when specifying %{body_format} as content-type, you must pass valid
|
49
|
-
%{body_format} in the request's 'body'
|
50
|
-
"
|
51
|
-
empty_message_body: 'empty message body supplied with %{body_format} content-type'
|
52
|
-
too_many_multipart_files: "the number of uploaded files exceeded the system's configured limit (%{limit})"
|
53
|
-
invalid_accept_header:
|
54
|
-
problem: 'invalid accept header'
|
55
|
-
resolution: '%{message}'
|
56
|
-
invalid_version_header:
|
57
|
-
problem: 'invalid version header'
|
58
|
-
resolution: '%{message}'
|
59
|
-
invalid_response: 'Invalid response'
|
59
|
+
values: 'does not have a valid value'
|
@@ -3,40 +3,19 @@
|
|
3
3
|
module Grape
|
4
4
|
module Middleware
|
5
5
|
module Auth
|
6
|
-
class Base
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@app = app
|
13
|
-
@options = options.shift
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
dup._call(env)
|
6
|
+
class Base < Grape::Middleware::Base
|
7
|
+
def initialize(app, **options)
|
8
|
+
super
|
9
|
+
@auth_strategy = Grape::Middleware::Auth::Strategies[options[:type]].tap do |auth_strategy|
|
10
|
+
raise Grape::Exceptions::UnknownAuthStrategy.new(strategy: options[:type]) unless auth_strategy
|
11
|
+
end
|
18
12
|
end
|
19
13
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
auth_proc_context = context
|
26
|
-
|
27
|
-
strategy_info = Grape::Middleware::Auth::Strategies[options[:type]]
|
28
|
-
|
29
|
-
throw(:error, status: 401, message: 'API Authorization Failed.') if strategy_info.blank?
|
30
|
-
|
31
|
-
strategy = strategy_info.create(@app, options) do |*args|
|
32
|
-
auth_proc_context.instance_exec(*args, &auth_proc)
|
33
|
-
end
|
34
|
-
|
35
|
-
strategy.call(env)
|
36
|
-
|
37
|
-
else
|
38
|
-
app.call(env)
|
39
|
-
end
|
14
|
+
def call!(env)
|
15
|
+
@env = env
|
16
|
+
@auth_strategy.create(app, options) do |*args|
|
17
|
+
context.instance_exec(*args, &options[:proc])
|
18
|
+
end.call(env)
|
40
19
|
end
|
41
20
|
end
|
42
21
|
end
|
@@ -4,40 +4,34 @@ module Grape
|
|
4
4
|
module Middleware
|
5
5
|
module Auth
|
6
6
|
module DSL
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
if type
|
14
|
-
namespace_inheritable(:auth, options.reverse_merge(type: type.to_sym, proc: block))
|
15
|
-
use Grape::Middleware::Auth::Base, namespace_inheritable(:auth)
|
16
|
-
else
|
17
|
-
namespace_inheritable(:auth)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Add HTTP Basic authorization to the API.
|
22
|
-
#
|
23
|
-
# @param [Hash] options A hash of options.
|
24
|
-
# @option options [String] :realm "API Authorization" The HTTP Basic realm.
|
25
|
-
def http_basic(options = {}, &block)
|
26
|
-
options[:realm] ||= 'API Authorization'
|
27
|
-
auth :http_basic, options, &block
|
7
|
+
def auth(type = nil, options = {}, &block)
|
8
|
+
if type
|
9
|
+
namespace_inheritable(:auth, options.reverse_merge(type: type.to_sym, proc: block))
|
10
|
+
use Grape::Middleware::Auth::Base, namespace_inheritable(:auth)
|
11
|
+
else
|
12
|
+
namespace_inheritable(:auth)
|
28
13
|
end
|
14
|
+
end
|
29
15
|
|
30
|
-
|
31
|
-
|
16
|
+
# Add HTTP Basic authorization to the API.
|
17
|
+
#
|
18
|
+
# @param [Hash] options A hash of options.
|
19
|
+
# @option options [String] :realm "API Authorization" The HTTP Basic realm.
|
20
|
+
def http_basic(options = {}, &block)
|
21
|
+
options[:realm] ||= 'API Authorization'
|
22
|
+
auth :http_basic, options, &block
|
23
|
+
end
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
options[:opaque] ||= 'secret'
|
37
|
-
end
|
25
|
+
def http_digest(options = {}, &block)
|
26
|
+
options[:realm] ||= 'API Authorization'
|
38
27
|
|
39
|
-
|
28
|
+
if options[:realm].respond_to?(:values_at)
|
29
|
+
options[:realm][:opaque] ||= 'secret'
|
30
|
+
else
|
31
|
+
options[:opaque] ||= 'secret'
|
40
32
|
end
|
33
|
+
|
34
|
+
auth :http_digest, options, &block
|
41
35
|
end
|
42
36
|
end
|
43
37
|
end
|
@@ -3,25 +3,18 @@
|
|
3
3
|
module Grape
|
4
4
|
module Middleware
|
5
5
|
class Base
|
6
|
-
include Helpers
|
7
6
|
include Grape::DSL::Headers
|
8
7
|
|
9
8
|
attr_reader :app, :env, :options
|
10
9
|
|
11
|
-
TEXT_HTML = 'text/html'
|
12
|
-
|
13
10
|
# @param [Rack Application] app The standard argument for a Rack middleware.
|
14
11
|
# @param [Hash] options A hash of options, simply stored for use by subclasses.
|
15
|
-
def initialize(app,
|
12
|
+
def initialize(app, **options)
|
16
13
|
@app = app
|
17
|
-
@options =
|
14
|
+
@options = merge_default_options(options)
|
18
15
|
@app_response = nil
|
19
16
|
end
|
20
17
|
|
21
|
-
def default_options
|
22
|
-
{}
|
23
|
-
end
|
24
|
-
|
25
18
|
def call(env)
|
26
19
|
dup.call!(env).to_a
|
27
20
|
end
|
@@ -54,10 +47,18 @@ module Grape
|
|
54
47
|
# @return [Response, nil] a Rack SPEC response or nil to call the application afterwards.
|
55
48
|
def after; end
|
56
49
|
|
50
|
+
def rack_request
|
51
|
+
@rack_request ||= Rack::Request.new(env)
|
52
|
+
end
|
53
|
+
|
54
|
+
def context
|
55
|
+
env[Grape::Env::API_ENDPOINT]
|
56
|
+
end
|
57
|
+
|
57
58
|
def response
|
58
59
|
return @app_response if @app_response.is_a?(Rack::Response)
|
59
60
|
|
60
|
-
@app_response = Rack::Response
|
61
|
+
@app_response = Rack::Response[*@app_response]
|
61
62
|
end
|
62
63
|
|
63
64
|
def content_types
|
@@ -73,7 +74,15 @@ module Grape
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def content_type
|
76
|
-
content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) ||
|
77
|
+
content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) || 'text/html'
|
78
|
+
end
|
79
|
+
|
80
|
+
def query_params
|
81
|
+
rack_request.GET
|
82
|
+
rescue Rack::QueryParser::ParamsTooDeepError
|
83
|
+
raise Grape::Exceptions::TooDeepParameters.new(Rack::Utils.param_depth_limit)
|
84
|
+
rescue Rack::Utils::ParameterTypeError
|
85
|
+
raise Grape::Exceptions::ConflictingTypes
|
77
86
|
end
|
78
87
|
|
79
88
|
private
|
@@ -90,6 +99,16 @@ module Grape
|
|
90
99
|
def content_types_indifferent_access
|
91
100
|
@content_types_indifferent_access ||= content_types.with_indifferent_access
|
92
101
|
end
|
102
|
+
|
103
|
+
def merge_default_options(options)
|
104
|
+
if respond_to?(:default_options)
|
105
|
+
default_options.deep_merge(options)
|
106
|
+
elsif self.class.const_defined?(:DEFAULT_OPTIONS)
|
107
|
+
self.class::DEFAULT_OPTIONS.deep_merge(options)
|
108
|
+
else
|
109
|
+
options
|
110
|
+
end
|
111
|
+
end
|
93
112
|
end
|
94
113
|
end
|
95
114
|
end
|
@@ -3,30 +3,22 @@
|
|
3
3
|
module Grape
|
4
4
|
module Middleware
|
5
5
|
class Error < Base
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
},
|
21
|
-
rescue_handlers: {}, # rescue handler blocks
|
22
|
-
base_only_rescue_handlers: {}, # rescue handler blocks rescuing only the base class
|
23
|
-
all_rescue_handler: nil # rescue handler block to rescue from all exceptions
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(app, *options)
|
6
|
+
DEFAULT_OPTIONS = {
|
7
|
+
default_status: 500,
|
8
|
+
default_message: '',
|
9
|
+
format: :txt,
|
10
|
+
rescue_all: false,
|
11
|
+
rescue_grape_exceptions: false,
|
12
|
+
rescue_subclasses: true,
|
13
|
+
rescue_options: {
|
14
|
+
backtrace: false,
|
15
|
+
original_exception: false
|
16
|
+
}.freeze
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
def initialize(app, **options)
|
28
20
|
super
|
29
|
-
self.class.include(
|
21
|
+
self.class.include(options[:helpers]) if options[:helpers]
|
30
22
|
end
|
31
23
|
|
32
24
|
def call!(env)
|
@@ -39,7 +31,7 @@ module Grape
|
|
39
31
|
private
|
40
32
|
|
41
33
|
def rack_response(status, headers, message)
|
42
|
-
message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] ==
|
34
|
+
message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
|
43
35
|
Rack::Response.new(Array.wrap(message), Rack::Utils.status_code(status), Grape::Util::Header.new.merge(headers))
|
44
36
|
end
|
45
37
|
|