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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +36 -14
  5. data/UPGRADING.md +56 -1
  6. data/grape.gemspec +1 -1
  7. data/lib/grape/api/instance.rb +3 -2
  8. data/lib/grape/api.rb +43 -66
  9. data/lib/grape/cookies.rb +31 -25
  10. data/lib/grape/dsl/api.rb +0 -2
  11. data/lib/grape/dsl/headers.rb +1 -1
  12. data/lib/grape/dsl/helpers.rb +1 -1
  13. data/lib/grape/dsl/inside_route.rb +6 -18
  14. data/lib/grape/dsl/parameters.rb +3 -3
  15. data/lib/grape/dsl/routing.rb +9 -1
  16. data/lib/grape/endpoint.rb +30 -33
  17. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  18. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  19. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  20. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  21. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  22. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
  23. data/lib/grape/extensions/hash.rb +2 -1
  24. data/lib/grape/extensions/hashie/mash.rb +3 -5
  25. data/lib/grape/locale/en.yml +44 -44
  26. data/lib/grape/middleware/auth/base.rb +11 -32
  27. data/lib/grape/middleware/auth/dsl.rb +23 -29
  28. data/lib/grape/middleware/base.rb +30 -11
  29. data/lib/grape/middleware/error.rb +16 -24
  30. data/lib/grape/middleware/formatter.rb +38 -72
  31. data/lib/grape/middleware/stack.rb +26 -36
  32. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -3
  33. data/lib/grape/middleware/versioner/base.rb +10 -18
  34. data/lib/grape/middleware/versioner/header.rb +1 -1
  35. data/lib/grape/middleware/versioner/param.rb +2 -3
  36. data/lib/grape/params_builder/base.rb +18 -0
  37. data/lib/grape/params_builder/hash.rb +11 -0
  38. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  39. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  40. data/lib/grape/params_builder.rb +32 -0
  41. data/lib/grape/request.rb +161 -22
  42. data/lib/grape/router/route.rb +1 -1
  43. data/lib/grape/router.rb +25 -7
  44. data/lib/grape/validations/params_scope.rb +8 -3
  45. data/lib/grape/validations/validators/base.rb +2 -2
  46. data/lib/grape/validations/validators/except_values_validator.rb +1 -1
  47. data/lib/grape/validations/validators/presence_validator.rb +1 -1
  48. data/lib/grape/validations/validators/regexp_validator.rb +1 -1
  49. data/lib/grape/version.rb +1 -1
  50. data/lib/grape.rb +13 -1
  51. metadata +18 -13
  52. data/lib/grape/error_formatter/jsonapi.rb +0 -7
  53. data/lib/grape/http/headers.rb +0 -56
  54. data/lib/grape/middleware/helpers.rb +0 -12
  55. data/lib/grape/parser/jsonapi.rb +0 -7
  56. data/lib/grape/util/lazy/object.rb +0 -45
@@ -23,14 +23,14 @@ module Grape
23
23
  # class API < Grape::API
24
24
  # desc "Get collection"
25
25
  # params do
26
- # build_with Grape::Extensions::Hashie::Mash::ParamBuilder
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 = nil)
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
@@ -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::Http::Headers::SUPPORTED_METHODS.each do |supported_method|
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 || ['/']
@@ -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, :headers, :params
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.call(endpoint) if blk.respond_to?(:call) }
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 ? endpoints.collect(&:routes).flatten : to_routes
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, default_path_settings)
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
- options[:app].endpoints if options[:app].respond_to?(:endpoints)
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 (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
258
- allow_header_value = allowed_methods.join(', ')
259
- raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allow_header_value)) unless options?
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 Grape::Http::Headers::ALLOW, allow_header_value
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
- cookies.write(header)
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
- def befores
335
- namespace_stackable(:befores)
336
- end
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 ConflictingTypes < Base
6
+ def initialize
7
+ super(message: compose_message(:conflicting_types), status: 400)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Exceptions
5
+ class InvalidParameters < Base
6
+ def initialize
7
+ super(message: compose_message(:invalid_parameters), status: 400)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Exceptions
5
+ class TooDeepParameters < Base
6
+ def initialize(limit)
7
+ super(message: compose_message(:too_deep_parameters, limit: limit), status: 400)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Exceptions
5
+ class UnknownAuthStrategy < Base
6
+ def initialize(strategy:)
7
+ super(message: compose_message(:unknown_auth_strategy, strategy: strategy))
8
+ end
9
+ end
10
+ end
11
+ 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
- namespace_inheritable(:build_params_with, Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder)
12
- end
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
- namespace_inheritable(:build_params_with, Grape::Extensions::Hash::ParamBuilder)
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
- def params_builder
14
- Grape::Extensions::Hashie::Mash::ParamBuilder
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
@@ -1,59 +1,59 @@
1
+ ---
1
2
  en:
2
3
  grape:
3
4
  errors:
4
- format: ! '%{attributes} %{message}'
5
+ format: '%{attributes} %{message}'
5
6
  messages:
6
- coerce: 'is invalid'
7
- presence: 'is missing'
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
- values: 'does not have a valid value'
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
- same_as: 'is not the same as %{parameter}'
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
- missing_vendor_option:
18
- problem: 'missing :vendor option'
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
- invalid_formatter: 'cannot convert %{klass} to %{to_format}'
32
- invalid_versioner_option:
33
- problem: 'unknown :using for versioner: %{strategy}'
34
- resolution: 'available strategy for :using is :path, :header, :accept_version_header, :param'
35
- unknown_validator: 'unknown validator: %{validator_type}'
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
- incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
39
- mutual_exclusion: 'are mutually exclusive'
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
- invalid_message_body:
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
- include Helpers
8
-
9
- attr_accessor :options, :app, :env
10
-
11
- def initialize(app, *options)
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 _call(env)
21
- self.env = env
22
-
23
- if options.key?(:type)
24
- auth_proc = options[:proc]
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
- extend ActiveSupport::Concern
8
-
9
- module ClassMethods
10
- # Add an authentication type to the API. Currently
11
- # only `:http_basic`, `:http_digest` are supported.
12
- def auth(type = nil, options = {}, &block)
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
- def http_digest(options = {}, &block)
31
- options[:realm] ||= 'API Authorization'
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
- if options[:realm].respond_to?(:values_at)
34
- options[:realm][:opaque] ||= 'secret'
35
- else
36
- options[:opaque] ||= 'secret'
37
- end
25
+ def http_digest(options = {}, &block)
26
+ options[:realm] ||= 'API Authorization'
38
27
 
39
- auth :http_digest, options, &block
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, *options)
12
+ def initialize(app, **options)
16
13
  @app = app
17
- @options = options.any? ? default_options.deep_merge(options.shift) : default_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.new(@app_response[2], @app_response[0], @app_response[1])
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]) || TEXT_HTML
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
- def default_options
7
- {
8
- default_status: 500, # default status returned on error
9
- default_message: '',
10
- format: :txt,
11
- helpers: nil,
12
- formatters: {},
13
- error_formatters: {},
14
- rescue_all: false, # true to rescue all exceptions
15
- rescue_grape_exceptions: false,
16
- rescue_subclasses: true, # rescue subclasses of exceptions listed
17
- rescue_options: {
18
- backtrace: false, # true to display backtrace, true to let Grape handle Grape::Exceptions
19
- original_exception: false # true to display exception
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(@options[:helpers]) if @options[:helpers]
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] == TEXT_HTML
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