grape 2.0.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +404 -334
  5. data/UPGRADING.md +279 -7
  6. data/grape.gemspec +8 -8
  7. data/lib/grape/api/instance.rb +34 -66
  8. data/lib/grape/api.rb +47 -70
  9. data/lib/grape/content_types.rb +13 -10
  10. data/lib/grape/cookies.rb +31 -24
  11. data/lib/grape/dry_types.rb +0 -2
  12. data/lib/grape/dsl/api.rb +0 -2
  13. data/lib/grape/dsl/desc.rb +49 -44
  14. data/lib/grape/dsl/headers.rb +2 -2
  15. data/lib/grape/dsl/helpers.rb +8 -4
  16. data/lib/grape/dsl/inside_route.rb +67 -54
  17. data/lib/grape/dsl/parameters.rb +10 -9
  18. data/lib/grape/dsl/request_response.rb +14 -18
  19. data/lib/grape/dsl/routing.rb +34 -17
  20. data/lib/grape/dsl/validations.rb +13 -0
  21. data/lib/grape/endpoint.rb +120 -118
  22. data/lib/grape/{util/env.rb → env.rb} +0 -5
  23. data/lib/grape/error_formatter/base.rb +51 -21
  24. data/lib/grape/error_formatter/json.rb +7 -15
  25. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  26. data/lib/grape/error_formatter/txt.rb +11 -17
  27. data/lib/grape/error_formatter/xml.rb +3 -13
  28. data/lib/grape/error_formatter.rb +5 -25
  29. data/lib/grape/exceptions/base.rb +18 -30
  30. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  31. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  32. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  33. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  34. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  35. data/lib/grape/exceptions/validation.rb +5 -6
  36. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  37. data/lib/grape/exceptions/validation_errors.rb +4 -6
  38. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
  39. data/lib/grape/extensions/hash.rb +7 -2
  40. data/lib/grape/extensions/hashie/mash.rb +3 -5
  41. data/lib/grape/formatter/base.rb +16 -0
  42. data/lib/grape/formatter/json.rb +4 -6
  43. data/lib/grape/formatter/serializable_hash.rb +1 -1
  44. data/lib/grape/formatter/txt.rb +3 -5
  45. data/lib/grape/formatter/xml.rb +4 -6
  46. data/lib/grape/formatter.rb +7 -25
  47. data/lib/grape/{util/json.rb → json.rb} +1 -3
  48. data/lib/grape/locale/en.yml +46 -42
  49. data/lib/grape/middleware/auth/base.rb +11 -34
  50. data/lib/grape/middleware/auth/dsl.rb +23 -31
  51. data/lib/grape/middleware/base.rb +41 -23
  52. data/lib/grape/middleware/error.rb +77 -76
  53. data/lib/grape/middleware/formatter.rb +48 -79
  54. data/lib/grape/middleware/globals.rb +1 -3
  55. data/lib/grape/middleware/stack.rb +26 -37
  56. data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
  57. data/lib/grape/middleware/versioner/base.rb +74 -0
  58. data/lib/grape/middleware/versioner/header.rb +59 -126
  59. data/lib/grape/middleware/versioner/param.rb +4 -25
  60. data/lib/grape/middleware/versioner/path.rb +10 -34
  61. data/lib/grape/middleware/versioner.rb +7 -14
  62. data/lib/grape/namespace.rb +4 -5
  63. data/lib/grape/params_builder/base.rb +18 -0
  64. data/lib/grape/params_builder/hash.rb +11 -0
  65. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  66. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  67. data/lib/grape/params_builder.rb +32 -0
  68. data/lib/grape/parser/base.rb +16 -0
  69. data/lib/grape/parser/json.rb +6 -8
  70. data/lib/grape/parser/xml.rb +6 -8
  71. data/lib/grape/parser.rb +5 -23
  72. data/lib/grape/path.rb +38 -60
  73. data/lib/grape/request.rb +161 -30
  74. data/lib/grape/router/base_route.rb +39 -0
  75. data/lib/grape/router/greedy_route.rb +20 -0
  76. data/lib/grape/router/pattern.rb +45 -31
  77. data/lib/grape/router/route.rb +28 -57
  78. data/lib/grape/router.rb +56 -43
  79. data/lib/grape/util/base_inheritable.rb +4 -4
  80. data/lib/grape/util/cache.rb +0 -3
  81. data/lib/grape/util/endpoint_configuration.rb +1 -1
  82. data/lib/grape/util/header.rb +13 -0
  83. data/lib/grape/util/inheritable_values.rb +0 -2
  84. data/lib/grape/util/lazy/block.rb +29 -0
  85. data/lib/grape/util/lazy/value.rb +38 -0
  86. data/lib/grape/util/lazy/value_array.rb +21 -0
  87. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  88. data/lib/grape/util/lazy/value_hash.rb +21 -0
  89. data/lib/grape/util/media_type.rb +70 -0
  90. data/lib/grape/util/registry.rb +27 -0
  91. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  92. data/lib/grape/util/stackable_values.rb +1 -6
  93. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  94. data/lib/grape/validations/attributes_doc.rb +38 -36
  95. data/lib/grape/validations/attributes_iterator.rb +1 -0
  96. data/lib/grape/validations/contract_scope.rb +34 -0
  97. data/lib/grape/validations/params_scope.rb +36 -32
  98. data/lib/grape/validations/types/array_coercer.rb +0 -2
  99. data/lib/grape/validations/types/dry_type_coercer.rb +9 -15
  100. data/lib/grape/validations/types/json.rb +0 -2
  101. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  102. data/lib/grape/validations/types/set_coercer.rb +0 -3
  103. data/lib/grape/validations/types.rb +0 -3
  104. data/lib/grape/validations/validator_factory.rb +2 -2
  105. data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
  106. data/lib/grape/validations/validators/base.rb +8 -11
  107. data/lib/grape/validations/validators/coerce_validator.rb +1 -1
  108. data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
  109. data/lib/grape/validations/validators/default_validator.rb +6 -2
  110. data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
  111. data/lib/grape/validations/validators/except_values_validator.rb +2 -2
  112. data/lib/grape/validations/validators/length_validator.rb +49 -0
  113. data/lib/grape/validations/validators/presence_validator.rb +1 -1
  114. data/lib/grape/validations/validators/regexp_validator.rb +2 -2
  115. data/lib/grape/validations/validators/values_validator.rb +20 -57
  116. data/lib/grape/validations.rb +8 -21
  117. data/lib/grape/version.rb +1 -1
  118. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  119. data/lib/grape.rb +42 -274
  120. metadata +45 -44
  121. data/lib/grape/eager_load.rb +0 -20
  122. data/lib/grape/http/headers.rb +0 -71
  123. data/lib/grape/middleware/helpers.rb +0 -12
  124. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  125. data/lib/grape/router/attribute_translator.rb +0 -63
  126. data/lib/grape/util/lazy_block.rb +0 -27
  127. data/lib/grape/util/lazy_object.rb +0 -43
  128. data/lib/grape/util/lazy_value.rb +0 -91
  129. data/lib/grape/util/registrable.rb +0 -15
  130. data/lib/grape/validations/types/build_coercer.rb +0 -94
@@ -9,7 +9,7 @@ module Grape
9
9
 
10
10
  attr_reader :status, :headers
11
11
 
12
- def initialize(status: nil, message: nil, headers: nil, **_options)
12
+ def initialize(status: nil, message: nil, headers: nil)
13
13
  super(message)
14
14
 
15
15
  @status = status
@@ -26,42 +26,32 @@ module Grape
26
26
  # if BASE_ATTRIBUTES_KEY.key respond to a string message, then short_message is returned
27
27
  # if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
28
28
  def compose_message(key, **attributes)
29
- short_message = translate_message(key, **attributes)
30
- if short_message.is_a? Hash
31
- @problem = problem(key, **attributes)
32
- @summary = summary(key, **attributes)
33
- @resolution = resolution(key, **attributes)
34
- [['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].each_with_object(+'') do |detail_array, message|
35
- message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
36
- message
37
- end
38
- else
39
- short_message
40
- end
41
- end
29
+ short_message = translate_message(key, attributes)
30
+ return short_message unless short_message.is_a?(Hash)
42
31
 
43
- def problem(key, **attributes)
44
- translate_message("#{key}.problem".to_sym, **attributes)
32
+ each_steps(key, attributes).with_object(+'') do |detail_array, message|
33
+ message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
34
+ end
45
35
  end
46
36
 
47
- def summary(key, **attributes)
48
- translate_message("#{key}.summary".to_sym, **attributes)
49
- end
37
+ def each_steps(key, attributes)
38
+ return enum_for(:each_steps, key, attributes) unless block_given?
50
39
 
51
- def resolution(key, **attributes)
52
- translate_message("#{key}.resolution".to_sym, **attributes)
40
+ yield 'Problem', translate_message(:"#{key}.problem", attributes)
41
+ yield 'Summary', translate_message(:"#{key}.summary", attributes)
42
+ yield 'Resolution', translate_message(:"#{key}.resolution", attributes)
53
43
  end
54
44
 
55
- def translate_attributes(keys, **options)
45
+ def translate_attributes(keys, options = {})
56
46
  keys.map do |key|
57
- translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key, **options)
47
+ translate("#{BASE_ATTRIBUTES_KEY}.#{key}", options.merge(default: key.to_s))
58
48
  end.join(', ')
59
49
  end
60
50
 
61
- def translate_message(key, **options)
51
+ def translate_message(key, options = {})
62
52
  case key
63
53
  when Symbol
64
- translate("#{BASE_MESSAGES_KEY}.#{key}", default: '', **options)
54
+ translate("#{BASE_MESSAGES_KEY}.#{key}", options.merge(default: ''))
65
55
  when Proc
66
56
  key.call
67
57
  else
@@ -69,14 +59,12 @@ module Grape
69
59
  end
70
60
  end
71
61
 
72
- def translate(key, **options)
73
- options = options.dup
74
- options[:default] &&= options[:default].to_s
62
+ def translate(key, options)
75
63
  message = ::I18n.translate(key, **options)
76
- message.presence || fallback_message(key, **options)
64
+ message.presence || fallback_message(key, options)
77
65
  end
78
66
 
79
- def fallback_message(key, **options)
67
+ def fallback_message(key, options)
80
68
  if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
81
69
  key
82
70
  else
@@ -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
@@ -1,19 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grape/exceptions/base'
4
-
5
3
  module Grape
6
4
  module Exceptions
7
- class Validation < Grape::Exceptions::Base
5
+ class Validation < Base
8
6
  attr_accessor :params, :message_key
9
7
 
10
- def initialize(params:, message: nil, **args)
8
+ def initialize(params:, message: nil, status: nil, headers: nil)
11
9
  @params = params
12
10
  if message
13
11
  @message_key = message if message.is_a?(Symbol)
14
- args[:message] = translate_message(message)
12
+ message = translate_message(message)
15
13
  end
16
- super(**args)
14
+
15
+ super(status: status, message: message, headers: headers)
17
16
  end
18
17
 
19
18
  # Remove all the unnecessary stuff from Grape::Exceptions::Base like status
@@ -6,6 +6,7 @@ module Grape
6
6
  attr_reader :errors
7
7
 
8
8
  def initialize(errors)
9
+ super()
9
10
  @errors = errors
10
11
  end
11
12
  end
@@ -1,20 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grape/exceptions/base'
4
-
5
3
  module Grape
6
4
  module Exceptions
7
- class ValidationErrors < Grape::Exceptions::Base
5
+ class ValidationErrors < Base
8
6
  ERRORS_FORMAT_KEY = 'grape.errors.format'
9
- DEFAULT_ERRORS_FORMAT = '%{attributes} %{message}'
7
+ DEFAULT_ERRORS_FORMAT = '%<attributes>s %<message>s'
10
8
 
11
9
  include Enumerable
12
10
 
13
11
  attr_reader :errors
14
12
 
15
- def initialize(errors: [], headers: {}, **_options)
13
+ def initialize(errors: [], headers: {})
16
14
  @errors = errors.group_by(&:params)
17
- super message: full_messages.join(', '), status: 400, headers: headers
15
+ super(message: full_messages.join(', '), status: 400, headers: headers)
18
16
  end
19
17
 
20
18
  def each
@@ -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,13 +7,18 @@ 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
14
15
  rack_params.deep_dup.tap do |params|
15
- params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
16
16
  params.deep_symbolize_keys!
17
+
18
+ if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
19
+ grape_routing_args.deep_symbolize_keys!
20
+ params.deep_merge!(grape_routing_args)
21
+ end
17
22
  end
18
23
  end
19
24
  end
@@ -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
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Formatter
5
+ class Base
6
+ def self.call(_object, _env)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def self.inherited(klass)
11
+ super
12
+ Formatter.register(klass)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,13 +2,11 @@
2
2
 
3
3
  module Grape
4
4
  module Formatter
5
- module Json
6
- class << self
7
- def call(object, _env)
8
- return object.to_json if object.respond_to?(:to_json)
5
+ class Json < Base
6
+ def self.call(object, _env)
7
+ return object.to_json if object.respond_to?(:to_json)
9
8
 
10
- ::Grape::Json.dump(object)
11
- end
9
+ ::Grape::Json.dump(object)
12
10
  end
13
11
  end
14
12
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Grape
4
4
  module Formatter
5
- module SerializableHash
5
+ class SerializableHash < Base
6
6
  class << self
7
7
  def call(object, _env)
8
8
  return object if object.is_a?(String)
@@ -2,11 +2,9 @@
2
2
 
3
3
  module Grape
4
4
  module Formatter
5
- module Txt
6
- class << self
7
- def call(object, _env)
8
- object.respond_to?(:to_txt) ? object.to_txt : object.to_s
9
- end
5
+ class Txt < Base
6
+ def self.call(object, _env)
7
+ object.respond_to?(:to_txt) ? object.to_txt : object.to_s
10
8
  end
11
9
  end
12
10
  end
@@ -2,13 +2,11 @@
2
2
 
3
3
  module Grape
4
4
  module Formatter
5
- module Xml
6
- class << self
7
- def call(object, _env)
8
- return object.to_xml if object.respond_to?(:to_xml)
5
+ class Xml < Base
6
+ def self.call(object, _env)
7
+ return object.to_xml if object.respond_to?(:to_xml)
9
8
 
10
- raise Grape::Exceptions::InvalidFormatter.new(object.class, 'xml')
11
- end
9
+ raise Grape::Exceptions::InvalidFormatter.new(object.class, 'xml')
12
10
  end
13
11
  end
14
12
  end
@@ -2,34 +2,16 @@
2
2
 
3
3
  module Grape
4
4
  module Formatter
5
- extend Util::Registrable
5
+ extend Grape::Util::Registry
6
6
 
7
- class << self
8
- def builtin_formatters
9
- @builtin_formatters ||= {
10
- json: Grape::Formatter::Json,
11
- jsonapi: Grape::Formatter::Json,
12
- serializable_hash: Grape::Formatter::SerializableHash,
13
- txt: Grape::Formatter::Txt,
14
- xml: Grape::Formatter::Xml
15
- }
16
- end
7
+ module_function
17
8
 
18
- def formatters(**options)
19
- builtin_formatters.merge(default_elements).merge!(options[:formatters] || {})
20
- end
9
+ DEFAULT_LAMBDA_FORMATTER = ->(obj, _env) { obj }
21
10
 
22
- def formatter_for(api_format, **options)
23
- spec = formatters(**options)[api_format]
24
- case spec
25
- when nil
26
- ->(obj, _env) { obj }
27
- when Symbol
28
- method(spec)
29
- else
30
- spec
31
- end
32
- end
11
+ def formatter_for(api_format, formatters)
12
+ return formatters[api_format] if formatters&.key?(api_format)
13
+
14
+ registry[api_format] || DEFAULT_LAMBDA_FORMATTER
33
15
  end
34
16
  end
35
17
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
-
5
3
  module Grape
6
- if Object.const_defined? :MultiJson
4
+ if defined?(::MultiJson)
7
5
  Json = ::MultiJson
8
6
  else
9
7
  Json = ::JSON
@@ -1,55 +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}'
13
- missing_vendor_option:
14
- problem: 'missing :vendor option'
15
- summary: 'when version using header, you must specify :vendor option'
16
- resolution: "eg: version 'v1', using: :header, vendor: 'twitter'"
17
- missing_mime_type:
18
- problem: 'missing mime type for %{new_format}'
19
- resolution:
20
- "you can choose existing mime type from Grape::ContentTypes::CONTENT_TYPES
21
- or add your own with content_type :%{new_format}, 'application/%{new_format}'
22
- "
23
- invalid_with_option_for_represent:
24
- problem: 'you must specify an entity class in the :with option'
25
- resolution: 'eg: represent User, :with => Entity::User'
26
- missing_option: 'you must specify :%{option} options'
27
- invalid_formatter: 'cannot convert %{klass} to %{to_format}'
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
- unknown_validator: 'unknown validator: %{validator_type}'
32
- unknown_options: 'unknown options: %{options}'
33
- unknown_parameter: 'unknown parameter: %{param}'
34
15
  incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
35
- mutual_exclusion: 'are mutually exclusive'
36
- at_least_one: 'are missing, at least one parameter must be provided'
37
- exactly_one: 'are missing, exactly one parameter must be provided'
38
- all_or_none: 'provide all or none of parameters'
39
- missing_group_type: 'group type is required'
40
- unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
41
- invalid_message_body:
42
- problem: "message body does not match declared format"
43
- resolution:
44
- "when specifying %{body_format} as content-type, you must pass valid
45
- %{body_format} in the request's 'body'
46
- "
47
- empty_message_body: 'empty message body supplied with %{body_format} content-type'
48
- too_many_multipart_files: "the number of uploaded files exceeded the system's configured limit (%{limit})"
49
16
  invalid_accept_header:
50
17
  problem: 'invalid accept header'
51
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'
52
25
  invalid_version_header:
53
26
  problem: 'invalid version header'
54
27
  resolution: '%{message}'
55
- invalid_response: 'Invalid response'
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'
34
+ length: 'is expected to have length within %{min} and %{max}'
35
+ length_is: 'is expected to have length exactly equal to %{is}'
36
+ length_max: 'is expected to have length less than or equal to %{max}'
37
+ length_min: 'is expected to have length greater than or equal to %{min}'
38
+ missing_group_type: 'group type is required'
39
+ missing_mime_type:
40
+ problem: 'missing mime type for %{new_format}'
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}'' '
42
+ missing_option: 'you must specify :%{option} options'
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}'
54
+ unknown_options: 'unknown options: %{options}'
55
+ unknown_parameter: 'unknown parameter: %{param}'
56
+ unknown_params_builder: 'unknown params_builder: %{params_builder_type}'
57
+ unknown_validator: 'unknown validator: %{validator_type}'
58
+ unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
59
+ values: 'does not have a valid value'
@@ -1,44 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/auth/basic'
4
-
5
3
  module Grape
6
4
  module Middleware
7
5
  module Auth
8
- class Base
9
- include Helpers
10
-
11
- attr_accessor :options, :app, :env
12
-
13
- def initialize(app, *options)
14
- @app = app
15
- @options = options.shift
16
- end
17
-
18
- def call(env)
19
- 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
20
12
  end
21
13
 
22
- def _call(env)
23
- self.env = env
24
-
25
- if options.key?(:type)
26
- auth_proc = options[:proc]
27
- auth_proc_context = context
28
-
29
- strategy_info = Grape::Middleware::Auth::Strategies[options[:type]]
30
-
31
- throw(:error, status: 401, message: 'API Authorization Failed.') if strategy_info.blank?
32
-
33
- strategy = strategy_info.create(@app, options) do |*args|
34
- auth_proc_context.instance_exec(*args, &auth_proc)
35
- end
36
-
37
- strategy.call(env)
38
-
39
- else
40
- app.call(env)
41
- 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)
42
19
  end
43
20
  end
44
21
  end
@@ -1,45 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/auth/basic'
4
-
5
3
  module Grape
6
4
  module Middleware
7
5
  module Auth
8
6
  module DSL
9
- extend ActiveSupport::Concern
10
-
11
- module ClassMethods
12
- # Add an authentication type to the API. Currently
13
- # only `:http_basic`, `:http_digest` are supported.
14
- def auth(type = nil, options = {}, &block)
15
- if type
16
- namespace_inheritable(:auth, options.reverse_merge(type: type.to_sym, proc: block))
17
- use Grape::Middleware::Auth::Base, namespace_inheritable(:auth)
18
- else
19
- namespace_inheritable(:auth)
20
- end
21
- end
22
-
23
- # Add HTTP Basic authorization to the API.
24
- #
25
- # @param [Hash] options A hash of options.
26
- # @option options [String] :realm "API Authorization" The HTTP Basic realm.
27
- def http_basic(options = {}, &block)
28
- options[:realm] ||= 'API Authorization'
29
- 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)
30
13
  end
14
+ end
31
15
 
32
- def http_digest(options = {}, &block)
33
- 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
34
24
 
35
- if options[:realm].respond_to?(:values_at)
36
- options[:realm][:opaque] ||= 'secret'
37
- else
38
- options[:opaque] ||= 'secret'
39
- end
25
+ def http_digest(options = {}, &block)
26
+ options[:realm] ||= 'API Authorization'
40
27
 
41
- auth :http_digest, options, &block
28
+ if options[:realm].respond_to?(:values_at)
29
+ options[:realm][:opaque] ||= 'secret'
30
+ else
31
+ options[:opaque] ||= 'secret'
42
32
  end
33
+
34
+ auth :http_digest, options, &block
43
35
  end
44
36
  end
45
37
  end