grape 0.14.0 → 0.15.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.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -4
  3. data/Gemfile.lock +13 -13
  4. data/README.md +290 -12
  5. data/UPGRADING.md +68 -1
  6. data/gemfiles/rails_3.gemfile +1 -1
  7. data/lib/grape.rb +8 -2
  8. data/lib/grape/api.rb +40 -34
  9. data/lib/grape/dsl/configuration.rb +2 -115
  10. data/lib/grape/dsl/desc.rb +101 -0
  11. data/lib/grape/dsl/headers.rb +16 -0
  12. data/lib/grape/dsl/helpers.rb +5 -9
  13. data/lib/grape/dsl/inside_route.rb +3 -11
  14. data/lib/grape/dsl/logger.rb +20 -0
  15. data/lib/grape/dsl/parameters.rb +12 -10
  16. data/lib/grape/dsl/request_response.rb +17 -4
  17. data/lib/grape/dsl/routing.rb +24 -7
  18. data/lib/grape/dsl/settings.rb +8 -2
  19. data/lib/grape/endpoint.rb +30 -26
  20. data/lib/grape/error_formatter.rb +31 -0
  21. data/lib/grape/error_formatter/base.rb +0 -28
  22. data/lib/grape/error_formatter/json.rb +13 -2
  23. data/lib/grape/error_formatter/txt.rb +3 -1
  24. data/lib/grape/error_formatter/xml.rb +3 -1
  25. data/lib/grape/exceptions/base.rb +11 -4
  26. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  27. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  28. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  29. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  30. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  31. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  32. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
  33. data/lib/grape/exceptions/method_not_allowed.rb +10 -0
  34. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  35. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  36. data/lib/grape/exceptions/missing_option.rb +1 -1
  37. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  38. data/lib/grape/exceptions/unknown_options.rb +1 -1
  39. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  40. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  41. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  42. data/lib/grape/exceptions/validation.rb +2 -1
  43. data/lib/grape/formatter.rb +31 -0
  44. data/lib/grape/middleware/base.rb +28 -2
  45. data/lib/grape/middleware/error.rb +24 -1
  46. data/lib/grape/middleware/formatter.rb +4 -3
  47. data/lib/grape/middleware/versioner/param.rb +13 -2
  48. data/lib/grape/parser.rb +29 -0
  49. data/lib/grape/util/sendfile_response.rb +19 -0
  50. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  51. data/lib/grape/validations/params_scope.rb +39 -9
  52. data/lib/grape/validations/types.rb +16 -0
  53. data/lib/grape/validations/validators/all_or_none.rb +1 -1
  54. data/lib/grape/validations/validators/allow_blank.rb +2 -2
  55. data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
  56. data/lib/grape/validations/validators/base.rb +26 -0
  57. data/lib/grape/validations/validators/coerce.rb +16 -14
  58. data/lib/grape/validations/validators/default.rb +1 -1
  59. data/lib/grape/validations/validators/exactly_one_of.rb +10 -1
  60. data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
  61. data/lib/grape/validations/validators/presence.rb +1 -1
  62. data/lib/grape/validations/validators/regexp.rb +2 -2
  63. data/lib/grape/validations/validators/values.rb +2 -2
  64. data/lib/grape/version.rb +1 -1
  65. data/spec/grape/api/custom_validations_spec.rb +156 -21
  66. data/spec/grape/api/namespace_parameters_in_route_spec.rb +38 -0
  67. data/spec/grape/api/optional_parameters_in_route_spec.rb +43 -0
  68. data/spec/grape/api/required_parameters_in_route_spec.rb +37 -0
  69. data/spec/grape/api_spec.rb +118 -60
  70. data/spec/grape/dsl/configuration_spec.rb +0 -75
  71. data/spec/grape/dsl/desc_spec.rb +77 -0
  72. data/spec/grape/dsl/headers_spec.rb +32 -0
  73. data/spec/grape/dsl/inside_route_spec.rb +0 -18
  74. data/spec/grape/dsl/logger_spec.rb +26 -0
  75. data/spec/grape/dsl/parameters_spec.rb +13 -7
  76. data/spec/grape/dsl/request_response_spec.rb +17 -3
  77. data/spec/grape/dsl/routing_spec.rb +8 -1
  78. data/spec/grape/dsl/settings_spec.rb +42 -0
  79. data/spec/grape/endpoint_spec.rb +60 -9
  80. data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
  81. data/spec/grape/exceptions/validation_spec.rb +7 -0
  82. data/spec/grape/integration/rack_sendfile_spec.rb +44 -0
  83. data/spec/grape/middleware/base_spec.rb +100 -0
  84. data/spec/grape/middleware/exception_spec.rb +1 -2
  85. data/spec/grape/middleware/formatter_spec.rb +12 -2
  86. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
  87. data/spec/grape/middleware/versioner/header_spec.rb +11 -1
  88. data/spec/grape/middleware/versioner/param_spec.rb +105 -1
  89. data/spec/grape/validations/params_scope_spec.rb +77 -0
  90. data/spec/grape/validations/validators/allow_blank_spec.rb +277 -0
  91. data/spec/grape/validations/validators/coerce_spec.rb +91 -0
  92. data/spec/grape/validations/validators/default_spec.rb +6 -0
  93. data/spec/grape/validations/validators/presence_spec.rb +27 -0
  94. data/spec/grape/validations/validators/regexp_spec.rb +36 -0
  95. data/spec/grape/validations/validators/values_spec.rb +44 -0
  96. data/spec/grape/validations_spec.rb +149 -4
  97. data/spec/spec_helper.rb +1 -0
  98. metadata +26 -5
  99. data/lib/grape/formatter/base.rb +0 -31
  100. data/lib/grape/parser/base.rb +0 -29
  101. data/pkg/grape-0.13.0.gem +0 -0
@@ -1,6 +1,73 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 0.15.0
5
+
6
+ #### Changes to availability of `:with` option of `rescue_from` method
7
+
8
+ The `:with` option of `rescue_from` does not accept value except Proc, String or Symbol now.
9
+
10
+ If you have been depending the old behavior, you should use lambda block instead.
11
+
12
+ ```ruby
13
+ class API < Grape::API
14
+ rescue_from :all, with: -> { Rack::Response.new('rescued with a method', 400) }
15
+ end
16
+ ```
17
+
18
+ #### Changes to behavior of `after` method of middleware on error
19
+
20
+ The `after` method of the middleware is now also called on error. The following code would work correctly.
21
+
22
+ ```ruby
23
+ class ErrorMiddleware < Grape::Middleware::Base
24
+ def after
25
+ return unless @app_response && @app_response[0] == 500
26
+ env['rack.logger'].debug("Raised error on #{env['PATH_INFO']}")
27
+ end
28
+ end
29
+ ```
30
+
31
+ See [#1147](https://github.com/ruby-grape/grape/issues/1147) and [#1240](https://github.com/ruby-grape/grape/issues/1240) for discussion of the issues.
32
+
33
+ A warning will be logged if an exception is raised in an `after` callback, which points you to middleware that was not called in the previous version and is called now.
34
+
35
+ ```
36
+ caught error of type NoMethodError in after callback inside Api::Middleware::SomeMiddleware : undefined method `headers' for nil:NilClass
37
+ ```
38
+
39
+ See [#1285](https://github.com/ruby-grape/grape/pull/1285) for more information.
40
+
41
+ #### Changes to Method Not Allowed routes
42
+
43
+ A `405 Method Not Allowed` error now causes `Grape::Exceptions::MethodNotAllowed` to be raised, which will be rescued via `rescue_from :all`. Restore old behavior with the following error handler.
44
+
45
+ ```ruby
46
+ rescue_from Grape::Exceptions::MethodNotAllowed do |e|
47
+ error! e.message, e.status, e.headers
48
+ end
49
+ ```
50
+
51
+ See [#1283](https://github.com/ruby-grape/grape/pull/1283) for more information.
52
+
53
+ #### Changes to Grape::Exceptions::Validation parameters
54
+
55
+ When raising `Grape::Exceptions::Validation` explicitly, replace `message_key` with `message`.
56
+
57
+ For example,
58
+
59
+ ```ruby
60
+ fail Grape::Exceptions::Validation, params: [:oauth_token_secret], message_key: :presence
61
+ ```
62
+
63
+ becomes
64
+
65
+ ```ruby
66
+ fail Grape::Exceptions::Validation, params: [:oauth_token_secret], message: :presence
67
+ ```
68
+
69
+ See [#1295](https://github.com/ruby-grape/grape/pull/1295) for more information.
70
+
4
71
  ### Upgrading to >= 0.14.0
5
72
 
6
73
  #### Changes to availability of DSL methods in filters
@@ -106,7 +173,7 @@ error!({ message: 'No such page.', id: 'missing_page' }, 404, { 'Content-Type' =
106
173
  `error!` also supports just passing a message. `error!('Server error.')` and `format: :json` returns the following JSON response
107
174
 
108
175
  ```
109
- { 'error': 'Server error. }
176
+ { 'error': 'Server error.' }
110
177
  ```
111
178
 
112
179
  with a status code of 500 and a Content Type of text/error.
@@ -2,7 +2,7 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'rails', '3.2.19'
5
+ gem 'rails', '3.2.22'
6
6
  gem 'rack-cache', '<= 1.2'
7
7
 
8
8
  group :development, :test do
@@ -15,6 +15,7 @@ require 'active_support/core_ext/array/wrap'
15
15
  require 'active_support/core_ext/hash/deep_merge'
16
16
  require 'active_support/core_ext/hash/reverse_merge'
17
17
  require 'active_support/core_ext/hash/except'
18
+ require 'active_support/core_ext/hash/conversions'
18
19
  require 'active_support/dependencies/autoload'
19
20
  require 'active_support/notifications'
20
21
  require 'multi_json'
@@ -40,6 +41,9 @@ module Grape
40
41
 
41
42
  autoload :Cookies
42
43
  autoload :Validations
44
+ autoload :ErrorFormatter
45
+ autoload :Formatter
46
+ autoload :Parser
43
47
  autoload :Request
44
48
  autoload :Env, 'grape/util/env'
45
49
  end
@@ -71,6 +75,7 @@ module Grape
71
75
  autoload :InvalidMessageBody
72
76
  autoload :InvalidAcceptHeader
73
77
  autoload :InvalidVersionHeader
78
+ autoload :MethodNotAllowed
74
79
  end
75
80
 
76
81
  module ErrorFormatter
@@ -83,7 +88,6 @@ module Grape
83
88
 
84
89
  module Formatter
85
90
  extend ActiveSupport::Autoload
86
- autoload :Base
87
91
  autoload :Json
88
92
  autoload :SerializableHash
89
93
  autoload :Txt
@@ -92,7 +96,6 @@ module Grape
92
96
 
93
97
  module Parser
94
98
  extend ActiveSupport::Autoload
95
- autoload :Base
96
99
  autoload :Json
97
100
  autoload :Xml
98
101
  end
@@ -129,6 +132,7 @@ module Grape
129
132
  autoload :InheritableSetting
130
133
  autoload :StrictHashConfiguration
131
134
  autoload :FileResponse
135
+ autoload :SendfileResponse
132
136
  end
133
137
 
134
138
  module DSL
@@ -145,6 +149,8 @@ module Grape
145
149
  autoload :RequestResponse
146
150
  autoload :Routing
147
151
  autoload :Validations
152
+ autoload :Logger
153
+ autoload :Desc
148
154
  end
149
155
  end
150
156
 
@@ -13,9 +13,8 @@ module Grape
13
13
 
14
14
  # Clears all defined routes, endpoints, etc., on this API.
15
15
  def reset!
16
- @route_set = Rack::Mount::RouteSet.new
17
- @endpoints = []
18
- @routes = nil
16
+ reset_endpoints!
17
+ reset_routes!
19
18
  reset_validations!
20
19
  end
21
20
 
@@ -44,20 +43,10 @@ module Grape
44
43
  instance.call(env)
45
44
  end
46
45
 
47
- # Create a scope without affecting the URL.
48
- #
49
- # @param _name [Symbol] Purely placebo, just allows to name the scope to
50
- # make the code more readable.
51
- def scope(_name = nil, &block)
52
- within_namespace do
53
- nest(block)
54
- end
55
- end
56
-
57
46
  # (see #cascade?)
58
47
  def cascade(value = nil)
59
48
  if value.nil?
60
- inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !!namespace_inheritable(:cascade) : true
49
+ inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
61
50
  else
62
51
  namespace_inheritable(:cascade, value)
63
52
  end
@@ -91,9 +80,7 @@ module Grape
91
80
  def inherit_settings(other_settings)
92
81
  top_level_setting.inherit_from other_settings.point_in_time_copy
93
82
 
94
- endpoints.each(&:reset_routes!)
95
-
96
- @routes = nil
83
+ reset_routes!
97
84
  end
98
85
  end
99
86
 
@@ -144,8 +131,15 @@ module Grape
144
131
  self.class.endpoints.each do |endpoint|
145
132
  routes = endpoint.routes
146
133
  routes.each do |route|
147
- methods_per_path[route.route_path] ||= []
148
- methods_per_path[route.route_path] << route.route_method
134
+ route_path = route.route_path
135
+ .gsub(/\(.*\)/, '') # ignore any optional portions
136
+ .gsub(%r{\:[^\/.?]+}, ':x') # substitute variable names to avoid conflicts
137
+
138
+ methods_per_path[route_path] ||= []
139
+ methods_per_path[route_path] << route.route_method
140
+
141
+ # using the :any shorthand produces [nil] for route methods, substitute all manually
142
+ methods_per_path[route_path] = %w(GET PUT POST DELETE PATCH HEAD OPTIONS) if methods_per_path[route_path].compact.empty?
149
143
  end
150
144
  end
151
145
 
@@ -157,33 +151,45 @@ module Grape
157
151
  without_versioning do
158
152
  methods_per_path.each do |path, methods|
159
153
  allowed_methods = methods.dup
154
+
160
155
  unless self.class.namespace_inheritable(:do_not_route_head)
161
156
  allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
162
157
  end
163
158
 
164
- allow_header = ([Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ')
159
+ allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ')
160
+
165
161
  unless self.class.namespace_inheritable(:do_not_route_options)
166
- unless allowed_methods.include?(Grape::Http::Headers::OPTIONS)
167
- self.class.options(path, {}) do
168
- header 'Allow', allow_header
169
- status 204
170
- ''
171
- end
172
- end
162
+ generate_options_method(path, allow_header) unless allowed_methods.include?(Grape::Http::Headers::OPTIONS)
173
163
  end
174
164
 
175
- not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
176
- not_allowed_methods << Grape::Http::Headers::OPTIONS if self.class.namespace_inheritable(:do_not_route_options)
177
- self.class.route(not_allowed_methods, path) do
178
- header 'Allow', allow_header
179
- status 405
180
- ''
181
- end
165
+ generate_not_allowed_method(path, allowed_methods, allow_header)
182
166
  end
183
167
  end
184
168
  end
185
169
  end
186
170
 
171
+ # Generate an 'OPTIONS' route for a pre-exisiting user defined route
172
+ def generate_options_method(path, allow_header)
173
+ self.class.options(path, {}) do
174
+ header 'Allow', allow_header
175
+ status 204
176
+ ''
177
+ end
178
+ end
179
+
180
+ # Generate a route that returns an HTTP 405 response for a user defined
181
+ # path on methods not specified
182
+ def generate_not_allowed_method(path, allowed_methods, allow_header)
183
+ not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
184
+ not_allowed_methods << Grape::Http::Headers::OPTIONS if self.class.namespace_inheritable(:do_not_route_options)
185
+
186
+ return if not_allowed_methods.empty?
187
+
188
+ self.class.route(not_allowed_methods, path) do
189
+ fail Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allow_header)
190
+ end
191
+ end
192
+
187
193
  # Allows definition of endpoints that ignore the versioning configuration
188
194
  # used by the rest of your API.
189
195
  def without_versioning(&_block)
@@ -6,122 +6,9 @@ module Grape
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  module ClassMethods
9
- attr_writer :logger
10
-
11
9
  include Grape::DSL::Settings
12
-
13
- # Set or retrive the configured logger. If none was configured, this
14
- # method will create a new one, logging to stdout.
15
- # @param logger [Object] the new logger to use
16
- def logger(logger = nil)
17
- if logger
18
- global_setting(:logger, logger)
19
- else
20
- global_setting(:logger) || global_setting(:logger, Logger.new($stdout))
21
- end
22
- end
23
-
24
- # Add a description to the next namespace or function.
25
- # @param description [String] descriptive string for this endpoint
26
- # or namespace
27
- # @param options [Hash] other properties you can set to describe the
28
- # endpoint or namespace. Optional.
29
- # @option options :detail [String] additional detail about this endpoint
30
- # @option options :params [Hash] param types and info. normally, you set
31
- # these via the `params` dsl method.
32
- # @option options :entity [Grape::Entity] the entity returned upon a
33
- # successful call to this action
34
- # @option options :http_codes [Array[Array]] possible HTTP codes this
35
- # endpoint may return, with their meanings, in a 2d array
36
- # @option options :named [String] a specific name to help find this route
37
- # @option options :headers [Hash] HTTP headers this method can accept
38
- # @yield a block yielding an instance context with methods mapping to
39
- # each of the above, except that :entity is also aliased as #success
40
- # and :http_codes is aliased as #failure.
41
- #
42
- # @example
43
- #
44
- # desc 'create a user'
45
- # post '/users' do
46
- # # ...
47
- # end
48
- #
49
- # desc 'find a user' do
50
- # detail 'locates the user from the given user ID'
51
- # failure [ [404, 'Couldn\'t find the given user' ] ]
52
- # success User::Entity
53
- # end
54
- # get '/user/:id' do
55
- # # ...
56
- # end
57
- #
58
- def desc(description, options = {}, &config_block)
59
- if block_given?
60
- config_class = Grape::DSL::Configuration.desc_container
61
-
62
- config_class.configure do
63
- description description
64
- end
65
-
66
- config_class.configure(&config_block)
67
- unless options.empty?
68
- warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.'
69
- end
70
- options = config_class.settings
71
- else
72
- options = options.merge(description: description)
73
- end
74
-
75
- namespace_setting :description, options
76
- route_setting :description, options
77
- end
78
-
79
- def description_field(field, value = nil)
80
- if value
81
- description = route_setting(:description)
82
- description ||= route_setting(:description, {})
83
- description[field] = value
84
- else
85
- description = route_setting(:description)
86
- description[field] if description
87
- end
88
- end
89
-
90
- def unset_description_field(field)
91
- description = route_setting(:description)
92
- description.delete(field) if description
93
- end
94
- end
95
-
96
- module_function
97
-
98
- # Merge multiple layers of settings into one hash.
99
- def stacked_hash_to_hash(settings)
100
- return if settings.blank?
101
- settings.each_with_object({}) { |value, result| result.deep_merge!(value) }
102
- end
103
-
104
- # Returns an object which configures itself via an instance-context DSL.
105
- def desc_container
106
- Module.new do
107
- include Grape::Util::StrictHashConfiguration.module(
108
- :description,
109
- :detail,
110
- :params,
111
- :entity,
112
- :http_codes,
113
- :named,
114
- :headers
115
- )
116
-
117
- def config_context.success(*args)
118
- entity(*args)
119
- end
120
-
121
- def config_context.failure(*args)
122
- http_codes(*args)
123
- end
124
- end
10
+ include Grape::DSL::Logger
11
+ include Grape::DSL::Desc
125
12
  end
126
13
  end
127
14
  end
@@ -0,0 +1,101 @@
1
+ module Grape
2
+ module DSL
3
+ module Desc
4
+ include Grape::DSL::Settings
5
+
6
+ # Add a description to the next namespace or function.
7
+ # @param description [String] descriptive string for this endpoint
8
+ # or namespace
9
+ # @param options [Hash] other properties you can set to describe the
10
+ # endpoint or namespace. Optional.
11
+ # @option options :detail [String] additional detail about this endpoint
12
+ # @option options :params [Hash] param types and info. normally, you set
13
+ # these via the `params` dsl method.
14
+ # @option options :entity [Grape::Entity] the entity returned upon a
15
+ # successful call to this action
16
+ # @option options :http_codes [Array[Array]] possible HTTP codes this
17
+ # endpoint may return, with their meanings, in a 2d array
18
+ # @option options :named [String] a specific name to help find this route
19
+ # @option options :headers [Hash] HTTP headers this method can accept
20
+ # @yield a block yielding an instance context with methods mapping to
21
+ # each of the above, except that :entity is also aliased as #success
22
+ # and :http_codes is aliased as #failure.
23
+ #
24
+ # @example
25
+ #
26
+ # desc 'create a user'
27
+ # post '/users' do
28
+ # # ...
29
+ # end
30
+ #
31
+ # desc 'find a user' do
32
+ # detail 'locates the user from the given user ID'
33
+ # failure [ [404, 'Couldn\'t find the given user' ] ]
34
+ # success User::Entity
35
+ # end
36
+ # get '/user/:id' do
37
+ # # ...
38
+ # end
39
+ #
40
+ def desc(description, options = {}, &config_block)
41
+ if block_given?
42
+ config_class = desc_container
43
+
44
+ config_class.configure do
45
+ description description
46
+ end
47
+
48
+ config_class.configure(&config_block)
49
+ unless options.empty?
50
+ warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.'
51
+ end
52
+ options = config_class.settings
53
+ else
54
+ options = options.merge(description: description)
55
+ end
56
+
57
+ namespace_setting :description, options
58
+ route_setting :description, options
59
+ end
60
+
61
+ def description_field(field, value = nil)
62
+ if value
63
+ description = route_setting(:description)
64
+ description ||= route_setting(:description, {})
65
+ description[field] = value
66
+ else
67
+ description = route_setting(:description)
68
+ description[field] if description
69
+ end
70
+ end
71
+
72
+ def unset_description_field(field)
73
+ description = route_setting(:description)
74
+ description.delete(field) if description
75
+ end
76
+
77
+ # Returns an object which configures itself via an instance-context DSL.
78
+ def desc_container
79
+ Module.new do
80
+ include Grape::Util::StrictHashConfiguration.module(
81
+ :description,
82
+ :detail,
83
+ :params,
84
+ :entity,
85
+ :http_codes,
86
+ :named,
87
+ :headers
88
+ )
89
+
90
+ def config_context.success(*args)
91
+ entity(*args)
92
+ end
93
+
94
+ def config_context.failure(*args)
95
+ http_codes(*args)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end