grape 0.6.1 → 0.7.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 +9 -9
- data/.gitignore +7 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +3 -3
- data/CHANGELOG.md +42 -3
- data/CONTRIBUTING.md +118 -0
- data/Gemfile +4 -4
- data/README.md +312 -52
- data/Rakefile +6 -1
- data/UPGRADING.md +124 -0
- data/lib/grape.rb +2 -0
- data/lib/grape/api.rb +95 -44
- data/lib/grape/cookies.rb +0 -2
- data/lib/grape/endpoint.rb +63 -39
- data/lib/grape/error_formatter/base.rb +0 -3
- data/lib/grape/error_formatter/json.rb +0 -2
- data/lib/grape/error_formatter/txt.rb +0 -2
- data/lib/grape/error_formatter/xml.rb +0 -2
- data/lib/grape/exceptions/base.rb +0 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +0 -3
- data/lib/grape/exceptions/invalid_formatter.rb +0 -3
- data/lib/grape/exceptions/invalid_versioner_option.rb +0 -4
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +0 -2
- data/lib/grape/exceptions/missing_mime_type.rb +0 -4
- data/lib/grape/exceptions/missing_option.rb +0 -3
- data/lib/grape/exceptions/missing_vendor_option.rb +0 -3
- data/lib/grape/exceptions/unknown_options.rb +0 -4
- data/lib/grape/exceptions/unknown_validator.rb +0 -2
- data/lib/grape/exceptions/validation_errors.rb +6 -5
- data/lib/grape/formatter/base.rb +0 -3
- data/lib/grape/formatter/json.rb +0 -2
- data/lib/grape/formatter/serializable_hash.rb +15 -16
- data/lib/grape/formatter/txt.rb +0 -2
- data/lib/grape/formatter/xml.rb +0 -2
- data/lib/grape/http/request.rb +2 -4
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/oauth2.rb +15 -6
- data/lib/grape/middleware/base.rb +7 -7
- data/lib/grape/middleware/error.rb +11 -6
- data/lib/grape/middleware/formatter.rb +80 -78
- data/lib/grape/middleware/globals.rb +13 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
- data/lib/grape/middleware/versioner/header.rb +5 -3
- data/lib/grape/middleware/versioner/param.rb +2 -4
- data/lib/grape/middleware/versioner/path.rb +3 -4
- data/lib/grape/namespace.rb +0 -1
- data/lib/grape/parser/base.rb +0 -3
- data/lib/grape/parser/json.rb +0 -2
- data/lib/grape/parser/xml.rb +0 -2
- data/lib/grape/path.rb +1 -3
- data/lib/grape/route.rb +0 -3
- data/lib/grape/util/hash_stack.rb +1 -1
- data/lib/grape/validations.rb +72 -22
- data/lib/grape/validations/coerce.rb +5 -4
- data/lib/grape/validations/default.rb +5 -3
- data/lib/grape/validations/presence.rb +1 -1
- data/lib/grape/validations/regexp.rb +0 -2
- data/lib/grape/validations/values.rb +2 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +385 -96
- data/spec/grape/endpoint_spec.rb +162 -15
- data/spec/grape/entity_spec.rb +25 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
- data/spec/grape/middleware/auth/oauth2_spec.rb +60 -15
- data/spec/grape/middleware/base_spec.rb +3 -8
- data/spec/grape/middleware/error_spec.rb +2 -2
- data/spec/grape/middleware/exception_spec.rb +4 -4
- data/spec/grape/middleware/formatter_spec.rb +7 -4
- data/spec/grape/middleware/versioner/param_spec.rb +8 -7
- data/spec/grape/path_spec.rb +24 -14
- data/spec/grape/util/hash_stack_spec.rb +8 -8
- data/spec/grape/validations/coerce_spec.rb +75 -33
- data/spec/grape/validations/default_spec.rb +57 -0
- data/spec/grape/validations/presence_spec.rb +13 -11
- data/spec/grape/validations/values_spec.rb +76 -2
- data/spec/grape/validations_spec.rb +443 -20
- data/spec/spec_helper.rb +2 -2
- data/spec/support/content_type_helpers.rb +11 -0
- metadata +9 -38
data/Rakefile
CHANGED
@@ -15,7 +15,12 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
task :spec
|
18
|
-
|
18
|
+
|
19
|
+
require 'rainbow/ext/string' unless String.respond_to?(:color)
|
20
|
+
require 'rubocop/rake_task'
|
21
|
+
Rubocop::RakeTask.new(:rubocop)
|
22
|
+
|
23
|
+
task default: [:rubocop, :spec]
|
19
24
|
|
20
25
|
begin
|
21
26
|
require 'yard'
|
data/UPGRADING.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
Upgrading Grape
|
2
|
+
===============
|
3
|
+
|
4
|
+
### Upgrading to 0.7.0
|
5
|
+
|
6
|
+
#### Changes in Exception Handling
|
7
|
+
|
8
|
+
Assume you have the following exception classes defined.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
class ParentError < StandardError; end
|
12
|
+
class ChildError < ParentError; end
|
13
|
+
```
|
14
|
+
|
15
|
+
In Grape <= 0.6.1, the `rescue_from` keyword only handled the exact exception being raised. The following code would rescue `ParentError`, but not `ChildError`.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
rescue_from ParentError do |e|
|
19
|
+
# only rescue ParentError
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
This made it impossible to rescue an exception hieararchy, which is a more sensible default. In Grape 0.7.0 or newer, both `ParentError` and `ChildError` are rescued.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
rescue_from ParentError do |e|
|
27
|
+
# rescue both ParentError and ChildError
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
To only rescue the base exception class, set `rescue_subclasses: false`.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
rescue_from ParentError, rescue_subclasses: false do |e|
|
35
|
+
# only rescue ParentError
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
See [#544](https://github.com/intridea/grape/pull/544) for more information.
|
40
|
+
|
41
|
+
|
42
|
+
#### Changes in the Default HTTP Status Code
|
43
|
+
|
44
|
+
In Grape <= 0.6.1, the default status code returned from `error!` was 403.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
error! "You may not reticulate this spline!" # yields HTTP error 403
|
48
|
+
```
|
49
|
+
|
50
|
+
This was a bad default value, since 403 means "Forbidden". Change any call to `error!` that does not specify a status code to specify one. The new default value is a more sensible default of 500, which is "Internal Server Error".
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
error! "You may not reticulate this spline!", 403 # yields HTTP error 403
|
54
|
+
```
|
55
|
+
|
56
|
+
You may also use `default_error_status` to change the global default.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
default_error_status 400
|
60
|
+
```
|
61
|
+
|
62
|
+
See [#525](https://github.com/intridea/Grape/pull/525) for more information.
|
63
|
+
|
64
|
+
|
65
|
+
#### Changes in Parameter Declaration and Validation
|
66
|
+
|
67
|
+
In Grape <= 0.6.1, `group`, `optional` and `requires` keywords with a block accepted either an `Array` or a `Hash`.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
params do
|
71
|
+
requires :id, type: Integer
|
72
|
+
group :name do
|
73
|
+
requires :first_name
|
74
|
+
requires :last_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
This caused the ambiguity and unexpected errors described in [#543](https://github.com/intridea/Grape/issues/543).
|
80
|
+
|
81
|
+
In Grape 0.6.2, the `group`, `optional` and `requires` keywords take an additional `type` attribute which defaults to `Array`. This means that without a `type` attribute, these nested parameters will no longer accept a single hash, only an array (of hashes).
|
82
|
+
|
83
|
+
Whereas in 0.6.1 the API above accepted the following json, it no longer does in 0.6.2.
|
84
|
+
|
85
|
+
```json
|
86
|
+
{
|
87
|
+
"id": 1,
|
88
|
+
"name": {
|
89
|
+
"first_name": "John",
|
90
|
+
"last_name" : "Doe"
|
91
|
+
}
|
92
|
+
}
|
93
|
+
```
|
94
|
+
|
95
|
+
The `params` block should now read as follows.
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
params do
|
99
|
+
requires :id, type: Integer
|
100
|
+
requires :name, type: Hash do
|
101
|
+
requires :first_name
|
102
|
+
requires :last_name
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
See [#545](https://github.com/intridea/Grape/pull/545) for more information.
|
108
|
+
|
109
|
+
|
110
|
+
### Upgrading to 0.6.0
|
111
|
+
|
112
|
+
In Grape <= 0.5.0, only the first validation error was raised and processing aborted. Validation errors are now collected and a single `Grape::Exceptions::ValidationErrors` exception is raised. You can access the collection of validation errors as `.errors`.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
rescue_from Grape::Exceptions::Validations do |e|
|
116
|
+
Rack::Response.new({
|
117
|
+
status: 422,
|
118
|
+
message: e.message,
|
119
|
+
errors: e.errors
|
120
|
+
}.to_json, 422)
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
For more information see [#462](https://github.com/intridea/grape/issues/462).
|
data/lib/grape.rb
CHANGED
@@ -6,6 +6,7 @@ require 'rack/accept'
|
|
6
6
|
require 'rack/auth/basic'
|
7
7
|
require 'rack/auth/digest/md5'
|
8
8
|
require 'hashie'
|
9
|
+
require 'set'
|
9
10
|
require 'active_support/core_ext/hash/indifferent_access'
|
10
11
|
require 'active_support/ordered_hash'
|
11
12
|
require 'active_support/core_ext/object/conversions'
|
@@ -16,6 +17,7 @@ require 'multi_json'
|
|
16
17
|
require 'multi_xml'
|
17
18
|
require 'virtus'
|
18
19
|
require 'i18n'
|
20
|
+
require 'thread'
|
19
21
|
|
20
22
|
I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
|
21
23
|
|
data/lib/grape/api.rb
CHANGED
@@ -9,6 +9,8 @@ module Grape
|
|
9
9
|
attr_reader :endpoints, :instance, :routes, :route_set, :settings, :versions
|
10
10
|
attr_writer :logger
|
11
11
|
|
12
|
+
LOCK = Mutex.new
|
13
|
+
|
12
14
|
def logger(logger = nil)
|
13
15
|
if logger
|
14
16
|
@logger = logger
|
@@ -26,7 +28,7 @@ module Grape
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def compile
|
29
|
-
@instance
|
31
|
+
@instance ||= new
|
30
32
|
end
|
31
33
|
|
32
34
|
def change!
|
@@ -34,7 +36,7 @@ module Grape
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def call(env)
|
37
|
-
compile unless instance
|
39
|
+
LOCK.synchronize { compile } unless instance
|
38
40
|
call!(env)
|
39
41
|
end
|
40
42
|
|
@@ -199,6 +201,7 @@ module Grape
|
|
199
201
|
# @param [Block] block Execution block to handle the given exception.
|
200
202
|
# @param [Hash] options Options for the rescue usage.
|
201
203
|
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
|
204
|
+
# @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
|
202
205
|
# @param [Proc] handler Execution proc to handle the given exception as an
|
203
206
|
# alternative to passing a block
|
204
207
|
def rescue_from(*args, &block)
|
@@ -211,19 +214,12 @@ module Grape
|
|
211
214
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
212
215
|
handler ||= proc { options[:with] } if options.has_key?(:with)
|
213
216
|
|
214
|
-
|
215
|
-
|
216
|
-
imbue(:rescue_handlers, { arg => handler })
|
217
|
-
end
|
218
|
-
end
|
217
|
+
handler_type = !!options[:rescue_subclasses] ? :rescue_handlers : :base_only_rescue_handlers
|
218
|
+
imbue handler_type, Hash[args.map { |arg| [arg, handler] }]
|
219
219
|
|
220
220
|
imbue(:rescue_options, options)
|
221
221
|
|
222
|
-
if args.include?(:all)
|
223
|
-
set(:rescue_all, true)
|
224
|
-
else
|
225
|
-
imbue(:rescued_errors, args)
|
226
|
-
end
|
222
|
+
set(:rescue_all, true) if args.include?(:all)
|
227
223
|
end
|
228
224
|
|
229
225
|
# Allows you to specify a default representation entity for a
|
@@ -274,11 +270,16 @@ module Grape
|
|
274
270
|
if block_given? || new_mod
|
275
271
|
mod = settings.peek[:helpers] || Module.new
|
276
272
|
if new_mod
|
273
|
+
inject_api_helpers_to_mod(new_mod) if new_mod.is_a?(Helpers)
|
277
274
|
mod.class_eval do
|
278
275
|
include new_mod
|
279
276
|
end
|
280
277
|
end
|
281
|
-
|
278
|
+
if block_given?
|
279
|
+
inject_api_helpers_to_mod(mod) do
|
280
|
+
mod.class_eval(&block)
|
281
|
+
end
|
282
|
+
end
|
282
283
|
set(:helpers, mod)
|
283
284
|
else
|
284
285
|
mod = Module.new
|
@@ -324,11 +325,12 @@ module Grape
|
|
324
325
|
app_settings.set :mount_path, mount_path
|
325
326
|
app.inherit_settings(app_settings)
|
326
327
|
end
|
327
|
-
endpoints << Grape::Endpoint.new(
|
328
|
+
endpoints << Grape::Endpoint.new(
|
329
|
+
settings.clone,
|
328
330
|
method: :any,
|
329
331
|
path: path,
|
330
332
|
app: app
|
331
|
-
|
333
|
+
)
|
332
334
|
end
|
333
335
|
end
|
334
336
|
|
@@ -360,6 +362,10 @@ module Grape
|
|
360
362
|
imbue(:befores, [block])
|
361
363
|
end
|
362
364
|
|
365
|
+
def before_validation(&block)
|
366
|
+
imbue(:before_validations, [block])
|
367
|
+
end
|
368
|
+
|
363
369
|
def after_validation(&block)
|
364
370
|
imbue(:after_validations, [block])
|
365
371
|
end
|
@@ -510,14 +516,20 @@ module Grape
|
|
510
516
|
e.options[:app].inherit_settings(other_stack) if e.options[:app].respond_to?(:inherit_settings, true)
|
511
517
|
end
|
512
518
|
end
|
519
|
+
|
520
|
+
def inject_api_helpers_to_mod(mod, &block)
|
521
|
+
mod.extend(Helpers)
|
522
|
+
yield if block_given?
|
523
|
+
mod.api_changed(self)
|
524
|
+
end
|
513
525
|
end
|
514
526
|
|
515
527
|
def initialize
|
516
528
|
@route_set = Rack::Mount::RouteSet.new
|
529
|
+
add_head_not_allowed_methods_and_options_methods
|
517
530
|
self.class.endpoints.each do |endpoint|
|
518
531
|
endpoint.mount_in(@route_set)
|
519
532
|
end
|
520
|
-
add_head_not_allowed_methods
|
521
533
|
@route_set.freeze
|
522
534
|
end
|
523
535
|
|
@@ -549,39 +561,78 @@ module Grape
|
|
549
561
|
# with a list of HTTP methods that can be called. Also add a route that
|
550
562
|
# will return an HTTP 405 response for any HTTP method that the resource
|
551
563
|
# cannot handle.
|
552
|
-
def
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
564
|
+
def add_head_not_allowed_methods_and_options_methods
|
565
|
+
methods_per_path = {}
|
566
|
+
self.class.endpoints.each do |endpoint|
|
567
|
+
routes = endpoint.routes
|
568
|
+
routes.each do |route|
|
569
|
+
methods_per_path[route.route_path] ||= []
|
570
|
+
methods_per_path[route.route_path] << route.route_method
|
559
571
|
end
|
560
572
|
end
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
573
|
+
|
574
|
+
# The paths we collected are prepared (cf. Path#prepare), so they
|
575
|
+
# contain already versioning information when using path versioning.
|
576
|
+
# Disable versioning so adding a route won't prepend versioning
|
577
|
+
# informations again.
|
578
|
+
without_versioning do
|
579
|
+
methods_per_path.each do |path, methods|
|
580
|
+
allowed_methods = methods.dup
|
581
|
+
unless self.class.settings[:do_not_route_head]
|
582
|
+
if allowed_methods.include?('GET')
|
583
|
+
allowed_methods = allowed_methods | ['HEAD']
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
allow_header = (['OPTIONS'] | allowed_methods).join(', ')
|
588
|
+
unless self.class.settings[:do_not_route_options]
|
589
|
+
unless allowed_methods.include?('OPTIONS')
|
590
|
+
self.class.options(path, {}) do
|
591
|
+
header 'Allow', allow_header
|
592
|
+
status 204
|
593
|
+
''
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
|
599
|
+
not_allowed_methods << 'OPTIONS' if self.class.settings[:do_not_route_options]
|
600
|
+
self.class.route(not_allowed_methods, path) do
|
601
|
+
header 'Allow', allow_header
|
602
|
+
status 405
|
603
|
+
''
|
604
|
+
end
|
582
605
|
end
|
583
606
|
end
|
584
607
|
end
|
585
608
|
|
609
|
+
def without_versioning(&block)
|
610
|
+
self.class.settings.push(version: nil, version_options: nil)
|
611
|
+
yield
|
612
|
+
self.class.settings.pop
|
613
|
+
end
|
614
|
+
|
615
|
+
# This module extends user defined helpers
|
616
|
+
# to provide some API-specific functionality
|
617
|
+
module Helpers
|
618
|
+
attr_accessor :api
|
619
|
+
def params(name, &block)
|
620
|
+
@named_params ||= {}
|
621
|
+
@named_params.merge! name => block
|
622
|
+
end
|
623
|
+
|
624
|
+
def api_changed(new_api)
|
625
|
+
@api = new_api
|
626
|
+
process_named_params
|
627
|
+
end
|
628
|
+
|
629
|
+
protected
|
630
|
+
|
631
|
+
def process_named_params
|
632
|
+
if @named_params && @named_params.any?
|
633
|
+
api.imbue(:named_params, @named_params)
|
634
|
+
end
|
635
|
+
end
|
636
|
+
end
|
586
637
|
end
|
587
638
|
end
|
data/lib/grape/cookies.rb
CHANGED
data/lib/grape/endpoint.rb
CHANGED
@@ -5,7 +5,7 @@ module Grape
|
|
5
5
|
# from inside a `get`, `post`, etc.
|
6
6
|
class Endpoint
|
7
7
|
attr_accessor :block, :source, :options, :settings
|
8
|
-
attr_reader :env, :request
|
8
|
+
attr_reader :env, :request, :headers, :params
|
9
9
|
|
10
10
|
class << self
|
11
11
|
# @api private
|
@@ -80,7 +80,7 @@ module Grape
|
|
80
80
|
route_set.add_route(self, {
|
81
81
|
path_info: route.route_compiled,
|
82
82
|
request_method: method,
|
83
|
-
},
|
83
|
+
}, route_info: route)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -146,6 +146,8 @@ module Grape
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def call!(env)
|
149
|
+
extend helpers
|
150
|
+
|
149
151
|
env['api.endpoint'] = self
|
150
152
|
if options[:app]
|
151
153
|
options[:app].call(env)
|
@@ -156,20 +158,22 @@ module Grape
|
|
156
158
|
end
|
157
159
|
end
|
158
160
|
|
159
|
-
# The parameters passed into the request as
|
160
|
-
# well as parsed from URL segments.
|
161
|
-
def params
|
162
|
-
@params ||= @request.params
|
163
|
-
end
|
164
|
-
|
165
161
|
# A filtering method that will return a hash
|
166
162
|
# consisting only of keys that have been declared by a
|
167
|
-
# `params` statement
|
163
|
+
# `params` statement against the current/target endpoint or parent
|
164
|
+
# namespaces
|
168
165
|
#
|
169
166
|
# @param params [Hash] The initial hash to filter. Usually this will just be `params`
|
170
|
-
# @param options [Hash] Can pass `:include_missing` and `:
|
171
|
-
|
167
|
+
# @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces`
|
168
|
+
# options. `:include_parent_namespaces` defaults to true, hence must be set to false if
|
169
|
+
# you want only to return params declared against the current/target endpoint
|
170
|
+
def declared(params, options = {}, declared_params = nil)
|
172
171
|
options[:include_missing] = true unless options.key?(:include_missing)
|
172
|
+
options[:include_parent_namespaces] = true unless options.key?(:include_parent_namespaces)
|
173
|
+
if declared_params.nil?
|
174
|
+
declared_params = !options[:include_parent_namespaces] ? settings[:declared_params] :
|
175
|
+
settings.gather(:declared_params)
|
176
|
+
end
|
173
177
|
|
174
178
|
unless declared_params
|
175
179
|
raise ArgumentError, "Tried to filter for declared parameters but none exist."
|
@@ -208,9 +212,10 @@ module Grape
|
|
208
212
|
# end user with the specified message.
|
209
213
|
#
|
210
214
|
# @param message [String] The message to display.
|
211
|
-
# @param status [Integer] the HTTP Status Code. Defaults to
|
212
|
-
def error!(message, status =
|
213
|
-
|
215
|
+
# @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
|
216
|
+
def error!(message, status = nil, headers = nil)
|
217
|
+
status = settings[:default_error_status] unless status
|
218
|
+
throw :error, message: message, status: status, headers: headers
|
214
219
|
end
|
215
220
|
|
216
221
|
# Redirect to a new url.
|
@@ -260,11 +265,6 @@ module Grape
|
|
260
265
|
end
|
261
266
|
end
|
262
267
|
|
263
|
-
# Retrieves all available request headers.
|
264
|
-
def headers
|
265
|
-
@headers ||= @request.headers
|
266
|
-
end
|
267
|
-
|
268
268
|
# Set response content-type
|
269
269
|
def content_type(val)
|
270
270
|
header('Content-Type', val)
|
@@ -324,14 +324,16 @@ module Grape
|
|
324
324
|
end
|
325
325
|
entity_class = options.delete(:with)
|
326
326
|
|
327
|
-
|
328
|
-
|
327
|
+
if entity_class.nil?
|
328
|
+
# entity class not explicitely defined, auto-detect from first object in the collection
|
329
|
+
object_instance = object.respond_to?(:first) ? object.first : object
|
329
330
|
|
330
|
-
|
331
|
-
|
332
|
-
|
331
|
+
object_instance.class.ancestors.each do |potential|
|
332
|
+
entity_class ||= (settings[:representations] || {})[potential]
|
333
|
+
end
|
333
334
|
|
334
|
-
|
335
|
+
entity_class ||= object_instance.class.const_get(:Entity) if object_instance.class.const_defined?(:Entity) && object_instance.class.const_get(:Entity).respond_to?(:represent)
|
336
|
+
end
|
335
337
|
|
336
338
|
root = options.delete(:root)
|
337
339
|
|
@@ -360,8 +362,6 @@ module Grape
|
|
360
362
|
env["rack.routing_args"][:route_info]
|
361
363
|
end
|
362
364
|
|
363
|
-
protected
|
364
|
-
|
365
365
|
# Return the collection of endpoints within this endpoint.
|
366
366
|
# This is the case when an Grape::API mounts another Grape::API.
|
367
367
|
def endpoints
|
@@ -372,16 +372,22 @@ module Grape
|
|
372
372
|
end
|
373
373
|
end
|
374
374
|
|
375
|
+
protected
|
376
|
+
|
375
377
|
def run(env)
|
376
378
|
@env = env
|
377
379
|
@header = {}
|
378
|
-
@request = Grape::Request.new(@env)
|
379
380
|
|
380
|
-
|
381
|
+
@request = Grape::Request.new(env)
|
382
|
+
@params = @request.params
|
383
|
+
@headers = @request.headers
|
384
|
+
|
381
385
|
cookies.read(@request)
|
382
386
|
|
383
387
|
run_filters befores
|
384
388
|
|
389
|
+
run_filters before_validations
|
390
|
+
|
385
391
|
# Retieve validations from this namespace and all parent namespaces.
|
386
392
|
validation_errors = []
|
387
393
|
settings.gather(:validations).each do |validator|
|
@@ -411,13 +417,14 @@ module Grape
|
|
411
417
|
b.use Rack::Head
|
412
418
|
b.use Grape::Middleware::Error,
|
413
419
|
format: settings[:format],
|
414
|
-
|
420
|
+
content_types: settings[:content_types],
|
421
|
+
default_status: settings[:default_error_status] || 500,
|
415
422
|
rescue_all: settings[:rescue_all],
|
416
|
-
rescued_errors: aggregate_setting(:rescued_errors),
|
417
423
|
default_error_formatter: settings[:default_error_formatter],
|
418
424
|
error_formatters: settings[:error_formatters],
|
419
425
|
rescue_options: settings[:rescue_options],
|
420
|
-
rescue_handlers: merged_setting(:rescue_handlers)
|
426
|
+
rescue_handlers: merged_setting(:rescue_handlers),
|
427
|
+
base_only_rescue_handlers: merged_setting(:base_only_rescue_handlers)
|
421
428
|
|
422
429
|
aggregate_setting(:middleware).each do |m|
|
423
430
|
m = m.dup
|
@@ -429,15 +436,28 @@ module Grape
|
|
429
436
|
end
|
430
437
|
end
|
431
438
|
|
432
|
-
|
433
|
-
|
439
|
+
if settings[:auth]
|
440
|
+
auth_proc = settings[:auth][:proc]
|
441
|
+
auth_proc_context = self
|
442
|
+
auth_middleware = {
|
443
|
+
http_basic: { class: Rack::Auth::Basic, args: [settings[:auth][:realm]] },
|
444
|
+
http_digest: { class: Rack::Auth::Digest::MD5, args: [settings[:auth][:realm], settings[:auth][:opaque]] }
|
445
|
+
}[settings[:auth][:type]]
|
446
|
+
|
447
|
+
# evaluate auth proc in context of endpoint
|
448
|
+
if auth_middleware
|
449
|
+
b.use auth_middleware[:class], *auth_middleware[:args] do |*args|
|
450
|
+
auth_proc_context.instance_exec(*args, &auth_proc)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
434
454
|
|
435
455
|
if settings[:version]
|
436
|
-
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]),
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
456
|
+
b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]),
|
457
|
+
versions: settings[:version] ? settings[:version].flatten : nil,
|
458
|
+
version_options: settings[:version_options],
|
459
|
+
prefix: settings[:root_prefix]
|
460
|
+
|
441
461
|
end
|
442
462
|
|
443
463
|
b.use Grape::Middleware::Formatter,
|
@@ -480,6 +500,10 @@ module Grape
|
|
480
500
|
aggregate_setting(:befores)
|
481
501
|
end
|
482
502
|
|
503
|
+
def before_validations
|
504
|
+
aggregate_setting(:before_validations)
|
505
|
+
end
|
506
|
+
|
483
507
|
def after_validations
|
484
508
|
aggregate_setting(:after_validations)
|
485
509
|
end
|