grape 0.8.0 → 0.9.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/.rubocop.yml +4 -2
- data/.rubocop_todo.yml +80 -0
- data/.travis.yml +2 -2
- data/CHANGELOG.md +21 -2
- data/Gemfile +1 -6
- data/Guardfile +1 -5
- data/README.md +110 -27
- data/Rakefile +1 -1
- data/UPGRADING.md +35 -0
- data/grape.gemspec +5 -2
- data/lib/grape.rb +20 -4
- data/lib/grape/api.rb +25 -467
- data/lib/grape/api/helpers.rb +7 -0
- data/lib/grape/dsl/callbacks.rb +27 -0
- data/lib/grape/dsl/configuration.rb +27 -0
- data/lib/grape/dsl/helpers.rb +86 -0
- data/lib/grape/dsl/inside_route.rb +227 -0
- data/lib/grape/dsl/middleware.rb +33 -0
- data/lib/grape/dsl/parameters.rb +79 -0
- data/lib/grape/dsl/request_response.rb +152 -0
- data/lib/grape/dsl/routing.rb +172 -0
- data/lib/grape/dsl/validations.rb +29 -0
- data/lib/grape/endpoint.rb +6 -226
- data/lib/grape/error_formatter/base.rb +28 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +6 -0
- data/lib/grape/exceptions/validation.rb +3 -3
- data/lib/grape/exceptions/validation_errors.rb +19 -6
- data/lib/grape/locale/en.yml +5 -3
- data/lib/grape/middleware/auth/base.rb +28 -12
- data/lib/grape/middleware/auth/dsl.rb +35 -0
- data/lib/grape/middleware/auth/strategies.rb +24 -0
- data/lib/grape/middleware/auth/strategy_info.rb +15 -0
- data/lib/grape/validations.rb +3 -92
- data/lib/grape/validations/at_least_one_of.rb +25 -0
- data/lib/grape/validations/coerce.rb +2 -2
- data/lib/grape/validations/exactly_one_of.rb +2 -2
- data/lib/grape/validations/mutual_exclusion.rb +2 -2
- data/lib/grape/validations/presence.rb +1 -1
- data/lib/grape/validations/regexp.rb +1 -1
- data/lib/grape/validations/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/helpers_spec.rb +36 -0
- data/spec/grape/api_spec.rb +72 -19
- data/spec/grape/dsl/callbacks_spec.rb +44 -0
- data/spec/grape/dsl/configuration_spec.rb +37 -0
- data/spec/grape/dsl/helpers_spec.rb +54 -0
- data/spec/grape/dsl/inside_route_spec.rb +222 -0
- data/spec/grape/dsl/middleware_spec.rb +40 -0
- data/spec/grape/dsl/parameters_spec.rb +108 -0
- data/spec/grape/dsl/request_response_spec.rb +123 -0
- data/spec/grape/dsl/routing_spec.rb +132 -0
- data/spec/grape/dsl/validations_spec.rb +55 -0
- data/spec/grape/endpoint_spec.rb +60 -11
- data/spec/grape/entity_spec.rb +9 -4
- data/spec/grape/exceptions/validation_errors_spec.rb +31 -1
- data/spec/grape/middleware/auth/base_spec.rb +34 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +53 -0
- data/spec/grape/middleware/auth/strategies_spec.rb +81 -0
- data/spec/grape/middleware/error_spec.rb +33 -1
- data/spec/grape/middleware/exception_spec.rb +13 -0
- data/spec/grape/validations/at_least_one_of_spec.rb +63 -0
- data/spec/grape/validations/exactly_one_of_spec.rb +1 -1
- data/spec/grape/validations/presence_spec.rb +159 -122
- data/spec/grape/validations/zh-CN.yml +1 -1
- data/spec/grape/validations_spec.rb +77 -15
- data/spec/spec_helper.rb +1 -0
- data/spec/support/endpoint_faker.rb +23 -0
- metadata +93 -15
- data/lib/grape/middleware/auth/basic.rb +0 -13
- data/lib/grape/middleware/auth/digest.rb +0 -13
- data/lib/grape/middleware/auth/oauth2.rb +0 -83
- data/spec/grape/middleware/auth/basic_spec.rb +0 -31
- data/spec/grape/middleware/auth/digest_spec.rb +0 -47
- data/spec/grape/middleware/auth/oauth2_spec.rb +0 -135
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module RequestResponse
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Specify the default format for the API's serializers.
|
10
|
+
# May be `:json` or `:txt` (default).
|
11
|
+
def default_format(new_format = nil)
|
12
|
+
new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Specify the format for the API's serializers.
|
16
|
+
# May be `:json`, `:xml`, `:txt`, etc.
|
17
|
+
def format(new_format = nil)
|
18
|
+
if new_format
|
19
|
+
set(:format, new_format.to_sym)
|
20
|
+
# define the default error formatters
|
21
|
+
set(:default_error_formatter, Grape::ErrorFormatter::Base.formatter_for(new_format, {}))
|
22
|
+
# define a single mime type
|
23
|
+
mime_type = content_types[new_format.to_sym]
|
24
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless mime_type
|
25
|
+
settings.imbue(:content_types, new_format.to_sym => mime_type)
|
26
|
+
else
|
27
|
+
settings[:format]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Specify a custom formatter for a content-type.
|
32
|
+
def formatter(content_type, new_formatter)
|
33
|
+
settings.imbue(:formatters, content_type.to_sym => new_formatter)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Specify a custom parser for a content-type.
|
37
|
+
def parser(content_type, new_parser)
|
38
|
+
settings.imbue(:parsers, content_type.to_sym => new_parser)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Specify a default error formatter.
|
42
|
+
def default_error_formatter(new_formatter_name = nil)
|
43
|
+
if new_formatter_name
|
44
|
+
new_formatter = Grape::ErrorFormatter::Base.formatter_for(new_formatter_name, {})
|
45
|
+
set(:default_error_formatter, new_formatter)
|
46
|
+
else
|
47
|
+
settings[:default_error_formatter]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_formatter(format, options)
|
52
|
+
if options.is_a?(Hash) && options.key?(:with)
|
53
|
+
formatter = options[:with]
|
54
|
+
else
|
55
|
+
formatter = options
|
56
|
+
end
|
57
|
+
|
58
|
+
settings.imbue(:error_formatters, format.to_sym => formatter)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Specify additional content-types, e.g.:
|
62
|
+
# content_type :xls, 'application/vnd.ms-excel'
|
63
|
+
def content_type(key, val)
|
64
|
+
settings.imbue(:content_types, key.to_sym => val)
|
65
|
+
end
|
66
|
+
|
67
|
+
# All available content types.
|
68
|
+
def content_types
|
69
|
+
Grape::ContentTypes.content_types_for(settings[:content_types])
|
70
|
+
end
|
71
|
+
|
72
|
+
# Specify the default status code for errors.
|
73
|
+
def default_error_status(new_status = nil)
|
74
|
+
new_status ? set(:default_error_status, new_status) : settings[:default_error_status]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Allows you to rescue certain exceptions that occur to return
|
78
|
+
# a grape error rather than raising all the way to the
|
79
|
+
# server level.
|
80
|
+
#
|
81
|
+
# @example Rescue from custom exceptions
|
82
|
+
# class ExampleAPI < Grape::API
|
83
|
+
# class CustomError < StandardError; end
|
84
|
+
#
|
85
|
+
# rescue_from CustomError
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# @overload rescue_from(*exception_classes, options = {})
|
89
|
+
# @param [Array] exception_classes A list of classes that you want to rescue, or
|
90
|
+
# the symbol :all to rescue from all exceptions.
|
91
|
+
# @param [Block] block Execution block to handle the given exception.
|
92
|
+
# @param [Hash] options Options for the rescue usage.
|
93
|
+
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
|
94
|
+
# @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
|
95
|
+
# @param [Proc] handler Execution proc to handle the given exception as an
|
96
|
+
# alternative to passing a block
|
97
|
+
def rescue_from(*args, &block)
|
98
|
+
if args.last.is_a?(Proc)
|
99
|
+
handler = args.pop
|
100
|
+
elsif block_given?
|
101
|
+
handler = block
|
102
|
+
end
|
103
|
+
|
104
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
105
|
+
handler ||= proc { options[:with] } if options.key?(:with)
|
106
|
+
|
107
|
+
if args.include?(:all)
|
108
|
+
set(:rescue_all, true)
|
109
|
+
imbue :all_rescue_handler, handler
|
110
|
+
else
|
111
|
+
handler_type =
|
112
|
+
case options[:rescue_subclasses]
|
113
|
+
when nil, true
|
114
|
+
:rescue_handlers
|
115
|
+
else
|
116
|
+
:base_only_rescue_handlers
|
117
|
+
end
|
118
|
+
|
119
|
+
imbue handler_type, Hash[args.map { |arg| [arg, handler] }]
|
120
|
+
end
|
121
|
+
|
122
|
+
imbue(:rescue_options, options)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Allows you to specify a default representation entity for a
|
126
|
+
# class. This allows you to map your models to their respective
|
127
|
+
# entities once and then simply call `present` with the model.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# class ExampleAPI < Grape::API
|
131
|
+
# represent User, with: Entity::User
|
132
|
+
#
|
133
|
+
# get '/me' do
|
134
|
+
# present current_user # with: Entity::User is assumed
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# Note that Grape will automatically go up the class ancestry to
|
139
|
+
# try to find a representing entity, so if you, for example, define
|
140
|
+
# an entity to represent `Object` then all presented objects will
|
141
|
+
# bubble up and utilize the entity provided on that `represent` call.
|
142
|
+
#
|
143
|
+
# @param model_class [Class] The model class that will be represented.
|
144
|
+
# @option options [Class] :with The entity class that will represent the model.
|
145
|
+
def represent(model_class, options)
|
146
|
+
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with] && options[:with].is_a?(Class)
|
147
|
+
imbue(:representations, model_class => options[:with])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module Routing
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
attr_reader :endpoints, :routes, :route_set
|
10
|
+
|
11
|
+
# Specify an API version.
|
12
|
+
#
|
13
|
+
# @example API with legacy support.
|
14
|
+
# class MyAPI < Grape::API
|
15
|
+
# version 'v2'
|
16
|
+
#
|
17
|
+
# get '/main' do
|
18
|
+
# {some: 'data'}
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# version 'v1' do
|
22
|
+
# get '/main' do
|
23
|
+
# {legacy: 'data'}
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
def version(*args, &block)
|
29
|
+
if args.any?
|
30
|
+
options = args.pop if args.last.is_a? Hash
|
31
|
+
options ||= {}
|
32
|
+
options = { using: :path }.merge(options)
|
33
|
+
|
34
|
+
raise Grape::Exceptions::MissingVendorOption.new if options[:using] == :header && !options.key?(:vendor)
|
35
|
+
|
36
|
+
@versions = versions | args
|
37
|
+
nest(block) do
|
38
|
+
set(:version, args)
|
39
|
+
set(:version_options, options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
@versions.last unless @versions.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Define a root URL prefix for your entire API.
|
47
|
+
def prefix(prefix = nil)
|
48
|
+
prefix ? set(:root_prefix, prefix) : settings[:root_prefix]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Do not route HEAD requests to GET requests automatically
|
52
|
+
def do_not_route_head!
|
53
|
+
set(:do_not_route_head, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Do not automatically route OPTIONS
|
57
|
+
def do_not_route_options!
|
58
|
+
set(:do_not_route_options, true)
|
59
|
+
end
|
60
|
+
|
61
|
+
def mount(mounts)
|
62
|
+
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
|
63
|
+
mounts.each_pair do |app, path|
|
64
|
+
if app.respond_to?(:inherit_settings, true)
|
65
|
+
app_settings = settings.clone
|
66
|
+
mount_path = Rack::Mount::Utils.normalize_path([settings[:mount_path], path].compact.join("/"))
|
67
|
+
app_settings.set :mount_path, mount_path
|
68
|
+
app.inherit_settings(app_settings)
|
69
|
+
end
|
70
|
+
endpoints << Grape::Endpoint.new(
|
71
|
+
settings.clone,
|
72
|
+
method: :any,
|
73
|
+
path: path,
|
74
|
+
app: app
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Defines a route that will be recognized
|
80
|
+
# by the Grape API.
|
81
|
+
#
|
82
|
+
# @param methods [HTTP Verb] One or more HTTP verbs that are accepted by this route. Set to `:any` if you want any verb to be accepted.
|
83
|
+
# @param paths [String] One or more strings representing the URL segment(s) for this route.
|
84
|
+
#
|
85
|
+
# @example Defining a basic route.
|
86
|
+
# class MyAPI < Grape::API
|
87
|
+
# route(:any, '/hello') do
|
88
|
+
# {hello: 'world'}
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
def route(methods, paths = ['/'], route_options = {}, &block)
|
92
|
+
endpoint_options = {
|
93
|
+
method: methods,
|
94
|
+
path: paths,
|
95
|
+
route_options: (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
|
96
|
+
}
|
97
|
+
endpoints << Grape::Endpoint.new(settings.clone, endpoint_options, &block)
|
98
|
+
|
99
|
+
@last_description = nil
|
100
|
+
reset_validations!
|
101
|
+
end
|
102
|
+
|
103
|
+
def get(paths = ['/'], options = {}, &block)
|
104
|
+
route('GET', paths, options, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def post(paths = ['/'], options = {}, &block)
|
108
|
+
route('POST', paths, options, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def put(paths = ['/'], options = {}, &block)
|
112
|
+
route('PUT', paths, options, &block)
|
113
|
+
end
|
114
|
+
|
115
|
+
def head(paths = ['/'], options = {}, &block)
|
116
|
+
route('HEAD', paths, options, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
def delete(paths = ['/'], options = {}, &block)
|
120
|
+
route('DELETE', paths, options, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def options(paths = ['/'], options = {}, &block)
|
124
|
+
route('OPTIONS', paths, options, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
def patch(paths = ['/'], options = {}, &block)
|
128
|
+
route('PATCH', paths, options, &block)
|
129
|
+
end
|
130
|
+
|
131
|
+
def namespace(space = nil, options = {}, &block)
|
132
|
+
if space || block_given?
|
133
|
+
previous_namespace_description = @namespace_description
|
134
|
+
@namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
|
135
|
+
@last_description = nil
|
136
|
+
nest(block) do
|
137
|
+
set(:namespace, Namespace.new(space, options)) if space
|
138
|
+
end
|
139
|
+
@namespace_description = previous_namespace_description
|
140
|
+
else
|
141
|
+
Namespace.joined_space_path(settings)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
alias_method :group, :namespace
|
146
|
+
alias_method :resource, :namespace
|
147
|
+
alias_method :resources, :namespace
|
148
|
+
alias_method :segment, :namespace
|
149
|
+
|
150
|
+
# An array of API routes.
|
151
|
+
def routes
|
152
|
+
@routes ||= prepare_routes
|
153
|
+
end
|
154
|
+
|
155
|
+
# Thie method allows you to quickly define a parameter route segment
|
156
|
+
# in your API.
|
157
|
+
#
|
158
|
+
# @param param [Symbol] The name of the parameter you wish to declare.
|
159
|
+
# @option options [Regexp] You may supply a regular expression that the declared parameter must meet.
|
160
|
+
def route_param(param, options = {}, &block)
|
161
|
+
options = options.dup
|
162
|
+
options[:requirements] = { param.to_sym => options[:requirements] } if options[:requirements].is_a?(Regexp)
|
163
|
+
namespace(":#{param}", options, &block)
|
164
|
+
end
|
165
|
+
|
166
|
+
def versions
|
167
|
+
@versions ||= []
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module DSL
|
5
|
+
module Validations
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def reset_validations!
|
10
|
+
settings.peek[:declared_params] = []
|
11
|
+
settings.peek[:validations] = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def params(&block)
|
15
|
+
Grape::Validations::ParamsScope.new(api: self, type: Hash, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def document_attribute(names, opts)
|
19
|
+
@last_description ||= {}
|
20
|
+
@last_description[:params] ||= {}
|
21
|
+
Array(names).each do |name|
|
22
|
+
@last_description[:params][name[:full_name].to_s] ||= {}
|
23
|
+
@last_description[:params][name[:full_name].to_s].merge!(opts)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/grape/endpoint.rb
CHANGED
@@ -7,6 +7,8 @@ module Grape
|
|
7
7
|
attr_accessor :block, :source, :options, :settings
|
8
8
|
attr_reader :env, :request, :headers, :params
|
9
9
|
|
10
|
+
include Grape::DSL::InsideRoute
|
11
|
+
|
10
12
|
class << self
|
11
13
|
def before_each(new_setup = false, &block)
|
12
14
|
if new_setup == false
|
@@ -49,6 +51,8 @@ module Grape
|
|
49
51
|
require_option(options, :method)
|
50
52
|
|
51
53
|
@settings = settings
|
54
|
+
@settings[:default_error_status] ||= 500
|
55
|
+
|
52
56
|
@options = options
|
53
57
|
|
54
58
|
@options[:path] = Array(options[:path])
|
@@ -92,7 +96,7 @@ module Grape
|
|
92
96
|
route_set.add_route(self, {
|
93
97
|
path_info: route.route_compiled,
|
94
98
|
request_method: method
|
95
|
-
|
99
|
+
}, route_info: route)
|
96
100
|
end
|
97
101
|
end
|
98
102
|
end
|
@@ -169,214 +173,6 @@ module Grape
|
|
169
173
|
end
|
170
174
|
end
|
171
175
|
|
172
|
-
# A filtering method that will return a hash
|
173
|
-
# consisting only of keys that have been declared by a
|
174
|
-
# `params` statement against the current/target endpoint or parent
|
175
|
-
# namespaces
|
176
|
-
#
|
177
|
-
# @param params [Hash] The initial hash to filter. Usually this will just be `params`
|
178
|
-
# @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces`
|
179
|
-
# options. `:include_parent_namespaces` defaults to true, hence must be set to false if
|
180
|
-
# you want only to return params declared against the current/target endpoint
|
181
|
-
def declared(params, options = {}, declared_params = nil)
|
182
|
-
options[:include_missing] = true unless options.key?(:include_missing)
|
183
|
-
options[:include_parent_namespaces] = true unless options.key?(:include_parent_namespaces)
|
184
|
-
if declared_params.nil?
|
185
|
-
declared_params = !options[:include_parent_namespaces] ? settings[:declared_params] :
|
186
|
-
settings.gather(:declared_params)
|
187
|
-
end
|
188
|
-
|
189
|
-
unless declared_params
|
190
|
-
raise ArgumentError, "Tried to filter for declared parameters but none exist."
|
191
|
-
end
|
192
|
-
|
193
|
-
if params.is_a? Array
|
194
|
-
params.map do |param|
|
195
|
-
declared(param || {}, options, declared_params)
|
196
|
-
end
|
197
|
-
else
|
198
|
-
declared_params.inject({}) do |hash, key|
|
199
|
-
key = { key => nil } unless key.is_a? Hash
|
200
|
-
|
201
|
-
key.each_pair do |parent, children|
|
202
|
-
output_key = options[:stringify] ? parent.to_s : parent.to_sym
|
203
|
-
if params.key?(parent) || options[:include_missing]
|
204
|
-
hash[output_key] = if children
|
205
|
-
declared(params[parent] || {}, options, Array(children))
|
206
|
-
else
|
207
|
-
params[parent]
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
hash
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# The API version as specified in the URL.
|
218
|
-
def version
|
219
|
-
env['api.version']
|
220
|
-
end
|
221
|
-
|
222
|
-
# End the request and display an error to the
|
223
|
-
# end user with the specified message.
|
224
|
-
#
|
225
|
-
# @param message [String] The message to display.
|
226
|
-
# @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
|
227
|
-
def error!(message, status = nil, headers = nil)
|
228
|
-
status = settings[:default_error_status] unless status
|
229
|
-
throw :error, message: message, status: status, headers: headers
|
230
|
-
end
|
231
|
-
|
232
|
-
# Redirect to a new url.
|
233
|
-
#
|
234
|
-
# @param url [String] The url to be redirect.
|
235
|
-
# @param options [Hash] The options used when redirect.
|
236
|
-
# :permanent, default true.
|
237
|
-
def redirect(url, options = {})
|
238
|
-
merged_options = { permanent: false }.merge(options)
|
239
|
-
if merged_options[:permanent]
|
240
|
-
status 301
|
241
|
-
else
|
242
|
-
if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase != "GET"
|
243
|
-
status 303
|
244
|
-
else
|
245
|
-
status 302
|
246
|
-
end
|
247
|
-
end
|
248
|
-
header "Location", url
|
249
|
-
body ""
|
250
|
-
end
|
251
|
-
|
252
|
-
# Set or retrieve the HTTP status code.
|
253
|
-
#
|
254
|
-
# @param status [Integer] The HTTP Status Code to return for this request.
|
255
|
-
def status(status = nil)
|
256
|
-
if status
|
257
|
-
@status = status
|
258
|
-
else
|
259
|
-
return @status if @status
|
260
|
-
case request.request_method.to_s.upcase
|
261
|
-
when 'POST'
|
262
|
-
201
|
263
|
-
else
|
264
|
-
200
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
# Set an individual header or retrieve
|
270
|
-
# all headers that have been set.
|
271
|
-
def header(key = nil, val = nil)
|
272
|
-
if key
|
273
|
-
val ? @header[key.to_s] = val : @header.delete(key.to_s)
|
274
|
-
else
|
275
|
-
@header
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
# Set response content-type
|
280
|
-
def content_type(val)
|
281
|
-
header('Content-Type', val)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Set or get a cookie
|
285
|
-
#
|
286
|
-
# @example
|
287
|
-
# cookies[:mycookie] = 'mycookie val'
|
288
|
-
# cookies['mycookie-string'] = 'mycookie string val'
|
289
|
-
# cookies[:more] = { value: '123', expires: Time.at(0) }
|
290
|
-
# cookies.delete :more
|
291
|
-
#
|
292
|
-
def cookies
|
293
|
-
@cookies ||= Cookies.new
|
294
|
-
end
|
295
|
-
|
296
|
-
# Allows you to define the response body as something other than the
|
297
|
-
# return value.
|
298
|
-
#
|
299
|
-
# @example
|
300
|
-
# get '/body' do
|
301
|
-
# body "Body"
|
302
|
-
# "Not the Body"
|
303
|
-
# end
|
304
|
-
#
|
305
|
-
# GET /body # => "Body"
|
306
|
-
def body(value = nil)
|
307
|
-
if value
|
308
|
-
@body = value
|
309
|
-
else
|
310
|
-
@body
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
# Allows you to make use of Grape Entities by setting
|
315
|
-
# the response body to the serializable hash of the
|
316
|
-
# entity provided in the `:with` option. This has the
|
317
|
-
# added benefit of automatically passing along environment
|
318
|
-
# and version information to the serialization, making it
|
319
|
-
# very easy to do conditional exposures. See Entity docs
|
320
|
-
# for more info.
|
321
|
-
#
|
322
|
-
# @example
|
323
|
-
#
|
324
|
-
# get '/users/:id' do
|
325
|
-
# present User.find(params[:id]),
|
326
|
-
# with: API::Entities::User,
|
327
|
-
# admin: current_user.admin?
|
328
|
-
# end
|
329
|
-
def present(*args)
|
330
|
-
options = args.count > 1 ? args.extract_options! : {}
|
331
|
-
key, object = if args.count == 2 && args.first.is_a?(Symbol)
|
332
|
-
args
|
333
|
-
else
|
334
|
-
[nil, args.first]
|
335
|
-
end
|
336
|
-
entity_class = options.delete(:with)
|
337
|
-
|
338
|
-
if entity_class.nil?
|
339
|
-
# entity class not explicitely defined, auto-detect from relation#klass or first object in the collection
|
340
|
-
object_class = if object.respond_to?(:klass)
|
341
|
-
object.klass
|
342
|
-
else
|
343
|
-
object.respond_to?(:first) ? object.first.class : object.class
|
344
|
-
end
|
345
|
-
|
346
|
-
object_class.ancestors.each do |potential|
|
347
|
-
entity_class ||= (settings[:representations] || {})[potential]
|
348
|
-
end
|
349
|
-
|
350
|
-
entity_class ||= object_class.const_get(:Entity) if object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
|
351
|
-
end
|
352
|
-
|
353
|
-
root = options.delete(:root)
|
354
|
-
|
355
|
-
representation = if entity_class
|
356
|
-
embeds = { env: env }
|
357
|
-
embeds[:version] = env['api.version'] if env['api.version']
|
358
|
-
entity_class.represent(object, embeds.merge(options))
|
359
|
-
else
|
360
|
-
object
|
361
|
-
end
|
362
|
-
|
363
|
-
representation = { root => representation } if root
|
364
|
-
representation = (@body || {}).merge(key => representation) if key
|
365
|
-
body representation
|
366
|
-
end
|
367
|
-
|
368
|
-
# Returns route information for the current request.
|
369
|
-
#
|
370
|
-
# @example
|
371
|
-
#
|
372
|
-
# desc "Returns the route description."
|
373
|
-
# get '/' do
|
374
|
-
# route.route_description
|
375
|
-
# end
|
376
|
-
def route
|
377
|
-
env["rack.routing_args"][:route_info]
|
378
|
-
end
|
379
|
-
|
380
176
|
# Return the collection of endpoints within this endpoint.
|
381
177
|
# This is the case when an Grape::API mounts another Grape::API.
|
382
178
|
def endpoints
|
@@ -435,7 +231,7 @@ module Grape
|
|
435
231
|
b.use Grape::Middleware::Error,
|
436
232
|
format: settings[:format],
|
437
233
|
content_types: settings[:content_types],
|
438
|
-
default_status: settings[:default_error_status]
|
234
|
+
default_status: settings[:default_error_status],
|
439
235
|
rescue_all: settings[:rescue_all],
|
440
236
|
default_error_formatter: settings[:default_error_formatter],
|
441
237
|
error_formatters: settings[:error_formatters],
|
@@ -454,22 +250,6 @@ module Grape
|
|
454
250
|
end
|
455
251
|
end
|
456
252
|
|
457
|
-
if settings[:auth]
|
458
|
-
auth_proc = settings[:auth][:proc]
|
459
|
-
auth_proc_context = self
|
460
|
-
auth_middleware = {
|
461
|
-
http_basic: { class: Rack::Auth::Basic, args: [settings[:auth][:realm]] },
|
462
|
-
http_digest: { class: Rack::Auth::Digest::MD5, args: [settings[:auth][:realm], settings[:auth][:opaque]] }
|
463
|
-
}[settings[:auth][:type]]
|
464
|
-
|
465
|
-
# evaluate auth proc in context of endpoint
|
466
|
-
if auth_middleware
|
467
|
-
b.use auth_middleware[:class], *auth_middleware[:args] do |*args|
|
468
|
-
auth_proc_context.instance_exec(*args, &auth_proc)
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
253
|
if settings[:version]
|
474
254
|
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]),
|
475
255
|
versions: settings[:version] ? settings[:version].flatten : nil,
|