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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -4
- data/Gemfile.lock +13 -13
- data/README.md +290 -12
- data/UPGRADING.md +68 -1
- data/gemfiles/rails_3.gemfile +1 -1
- data/lib/grape.rb +8 -2
- data/lib/grape/api.rb +40 -34
- data/lib/grape/dsl/configuration.rb +2 -115
- data/lib/grape/dsl/desc.rb +101 -0
- data/lib/grape/dsl/headers.rb +16 -0
- data/lib/grape/dsl/helpers.rb +5 -9
- data/lib/grape/dsl/inside_route.rb +3 -11
- data/lib/grape/dsl/logger.rb +20 -0
- data/lib/grape/dsl/parameters.rb +12 -10
- data/lib/grape/dsl/request_response.rb +17 -4
- data/lib/grape/dsl/routing.rb +24 -7
- data/lib/grape/dsl/settings.rb +8 -2
- data/lib/grape/endpoint.rb +30 -26
- data/lib/grape/error_formatter.rb +31 -0
- data/lib/grape/error_formatter/base.rb +0 -28
- data/lib/grape/error_formatter/json.rb +13 -2
- data/lib/grape/error_formatter/txt.rb +3 -1
- data/lib/grape/error_formatter/xml.rb +3 -1
- data/lib/grape/exceptions/base.rb +11 -4
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_message_body.rb +1 -1
- data/lib/grape/exceptions/invalid_version_header.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
- data/lib/grape/exceptions/method_not_allowed.rb +10 -0
- data/lib/grape/exceptions/missing_group_type.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/missing_option.rb +1 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
- data/lib/grape/exceptions/unknown_options.rb +1 -1
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
- data/lib/grape/exceptions/validation.rb +2 -1
- data/lib/grape/formatter.rb +31 -0
- data/lib/grape/middleware/base.rb +28 -2
- data/lib/grape/middleware/error.rb +24 -1
- data/lib/grape/middleware/formatter.rb +4 -3
- data/lib/grape/middleware/versioner/param.rb +13 -2
- data/lib/grape/parser.rb +29 -0
- data/lib/grape/util/sendfile_response.rb +19 -0
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/params_scope.rb +39 -9
- data/lib/grape/validations/types.rb +16 -0
- data/lib/grape/validations/validators/all_or_none.rb +1 -1
- data/lib/grape/validations/validators/allow_blank.rb +2 -2
- data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
- data/lib/grape/validations/validators/base.rb +26 -0
- data/lib/grape/validations/validators/coerce.rb +16 -14
- data/lib/grape/validations/validators/default.rb +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -1
- data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
- data/lib/grape/validations/validators/presence.rb +1 -1
- data/lib/grape/validations/validators/regexp.rb +2 -2
- data/lib/grape/validations/validators/values.rb +2 -2
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/custom_validations_spec.rb +156 -21
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +38 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +43 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +37 -0
- data/spec/grape/api_spec.rb +118 -60
- data/spec/grape/dsl/configuration_spec.rb +0 -75
- data/spec/grape/dsl/desc_spec.rb +77 -0
- data/spec/grape/dsl/headers_spec.rb +32 -0
- data/spec/grape/dsl/inside_route_spec.rb +0 -18
- data/spec/grape/dsl/logger_spec.rb +26 -0
- data/spec/grape/dsl/parameters_spec.rb +13 -7
- data/spec/grape/dsl/request_response_spec.rb +17 -3
- data/spec/grape/dsl/routing_spec.rb +8 -1
- data/spec/grape/dsl/settings_spec.rb +42 -0
- data/spec/grape/endpoint_spec.rb +60 -9
- data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
- data/spec/grape/exceptions/validation_spec.rb +7 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +44 -0
- data/spec/grape/middleware/base_spec.rb +100 -0
- data/spec/grape/middleware/exception_spec.rb +1 -2
- data/spec/grape/middleware/formatter_spec.rb +12 -2
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
- data/spec/grape/middleware/versioner/header_spec.rb +11 -1
- data/spec/grape/middleware/versioner/param_spec.rb +105 -1
- data/spec/grape/validations/params_scope_spec.rb +77 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +277 -0
- data/spec/grape/validations/validators/coerce_spec.rb +91 -0
- data/spec/grape/validations/validators/default_spec.rb +6 -0
- data/spec/grape/validations/validators/presence_spec.rb +27 -0
- data/spec/grape/validations/validators/regexp_spec.rb +36 -0
- data/spec/grape/validations/validators/values_spec.rb +44 -0
- data/spec/grape/validations_spec.rb +149 -4
- data/spec/spec_helper.rb +1 -0
- metadata +26 -5
- data/lib/grape/formatter/base.rb +0 -31
- data/lib/grape/parser/base.rb +0 -29
- data/pkg/grape-0.13.0.gem +0 -0
data/UPGRADING.md
CHANGED
@@ -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.
|
data/gemfiles/rails_3.gemfile
CHANGED
data/lib/grape.rb
CHANGED
@@ -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
|
|
data/lib/grape/api.rb
CHANGED
@@ -13,9 +13,8 @@ module Grape
|
|
13
13
|
|
14
14
|
# Clears all defined routes, endpoints, etc., on this API.
|
15
15
|
def reset!
|
16
|
-
|
17
|
-
|
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) ?
|
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
|
-
|
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
|
-
|
148
|
-
|
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
|
-
|
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
|
-
|
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
|