grape 0.9.0 → 0.10.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 +1 -66
- data/.rubocop_todo.yml +78 -17
- data/.travis.yml +7 -3
- data/Appraisals +7 -0
- data/CHANGELOG.md +24 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +1 -7
- data/Guardfile +1 -1
- data/README.md +560 -94
- data/RELEASING.md +1 -1
- data/Rakefile +10 -11
- data/UPGRADING.md +211 -3
- data/gemfiles/rails_3.gemfile +14 -0
- data/gemfiles/rails_4.gemfile +14 -0
- data/grape.gemspec +10 -9
- data/lib/backports/active_support/deep_dup.rb +49 -0
- data/lib/backports/active_support/duplicable.rb +88 -0
- data/lib/grape.rb +29 -2
- data/lib/grape/api.rb +59 -65
- data/lib/grape/dsl/api.rb +19 -0
- data/lib/grape/dsl/callbacks.rb +6 -4
- data/lib/grape/dsl/configuration.rb +49 -5
- data/lib/grape/dsl/helpers.rb +7 -8
- data/lib/grape/dsl/inside_route.rb +22 -10
- data/lib/grape/dsl/middleware.rb +5 -5
- data/lib/grape/dsl/parameters.rb +6 -2
- data/lib/grape/dsl/request_response.rb +23 -20
- data/lib/grape/dsl/routing.rb +52 -49
- data/lib/grape/dsl/settings.rb +110 -0
- data/lib/grape/dsl/validations.rb +14 -6
- data/lib/grape/endpoint.rb +104 -88
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.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/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_validator.rb +1 -1
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/xml.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/dsl.rb +26 -21
- data/lib/grape/middleware/auth/strategies.rb +1 -1
- data/lib/grape/middleware/auth/strategy_info.rb +0 -2
- data/lib/grape/middleware/base.rb +2 -2
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/middleware/versioner.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +3 -3
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/path.rb +9 -3
- data/lib/grape/util/content_types.rb +16 -8
- data/lib/grape/util/inheritable_setting.rb +74 -0
- data/lib/grape/util/inheritable_values.rb +51 -0
- data/lib/grape/util/stackable_values.rb +52 -0
- data/lib/grape/util/strict_hash_configuration.rb +106 -0
- data/lib/grape/validations.rb +0 -220
- data/lib/grape/validations/attributes_iterator.rb +21 -0
- data/lib/grape/validations/params_scope.rb +176 -0
- data/lib/grape/validations/validators/all_or_none.rb +20 -0
- data/lib/grape/validations/validators/allow_blank.rb +30 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +20 -0
- data/lib/grape/validations/validators/base.rb +37 -0
- data/lib/grape/validations/{coerce.rb → validators/coerce.rb} +3 -3
- data/lib/grape/validations/{default.rb → validators/default.rb} +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +20 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +26 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +25 -0
- data/lib/grape/validations/{presence.rb → validators/presence.rb} +2 -2
- data/lib/grape/validations/validators/regexp.rb +12 -0
- data/lib/grape/validations/validators/values.rb +26 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +522 -343
- data/spec/grape/dsl/callbacks_spec.rb +4 -4
- data/spec/grape/dsl/configuration_spec.rb +48 -9
- data/spec/grape/dsl/helpers_spec.rb +6 -13
- data/spec/grape/dsl/inside_route_spec.rb +43 -4
- data/spec/grape/dsl/middleware_spec.rb +1 -10
- data/spec/grape/dsl/parameters_spec.rb +8 -1
- data/spec/grape/dsl/request_response_spec.rb +16 -22
- data/spec/grape/dsl/routing_spec.rb +21 -5
- data/spec/grape/dsl/settings_spec.rb +219 -0
- data/spec/grape/dsl/validations_spec.rb +8 -11
- data/spec/grape/endpoint_spec.rb +115 -86
- data/spec/grape/entity_spec.rb +33 -33
- data/spec/grape/exceptions/invalid_formatter_spec.rb +3 -5
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +4 -6
- data/spec/grape/exceptions/missing_mime_type_spec.rb +5 -6
- data/spec/grape/exceptions/missing_option_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_options_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_validator_spec.rb +3 -5
- data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
- data/spec/grape/loading_spec.rb +44 -0
- data/spec/grape/middleware/auth/base_spec.rb +0 -4
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -4
- data/spec/grape/middleware/auth/strategies_spec.rb +5 -6
- data/spec/grape/middleware/exception_spec.rb +8 -10
- data/spec/grape/middleware/formatter_spec.rb +13 -15
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +10 -10
- data/spec/grape/middleware/versioner/header_spec.rb +25 -25
- data/spec/grape/middleware/versioner/param_spec.rb +15 -17
- data/spec/grape/middleware/versioner/path_spec.rb +1 -2
- data/spec/grape/middleware/versioner_spec.rb +0 -1
- data/spec/grape/path_spec.rb +66 -45
- data/spec/grape/util/inheritable_setting_spec.rb +217 -0
- data/spec/grape/util/inheritable_values_spec.rb +63 -0
- data/spec/grape/util/stackable_values_spec.rb +115 -0
- data/spec/grape/util/strict_hash_configuration_spec.rb +38 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +4 -0
- data/spec/grape/validations/params_scope_spec.rb +57 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +60 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +170 -0
- data/spec/grape/validations/{at_least_one_of_spec.rb → validators/at_least_one_of_spec.rb} +7 -3
- data/spec/grape/validations/{coerce_spec.rb → validators/coerce_spec.rb} +8 -11
- data/spec/grape/validations/{default_spec.rb → validators/default_spec.rb} +7 -9
- data/spec/grape/validations/{exactly_one_of_spec.rb → validators/exactly_one_of_spec.rb} +15 -11
- data/spec/grape/validations/{mutual_exclusion_spec.rb → validators/mutual_exclusion_spec.rb} +11 -9
- data/spec/grape/validations/{presence_spec.rb → validators/presence_spec.rb} +30 -30
- data/spec/grape/validations/{regexp_spec.rb → validators/regexp_spec.rb} +2 -4
- data/spec/grape/validations/{values_spec.rb → validators/values_spec.rb} +95 -23
- data/spec/grape/validations/{zh-CN.yml → validators/zh-CN.yml} +0 -0
- data/spec/grape/validations_spec.rb +335 -70
- data/spec/shared/versioning_examples.rb +7 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/content_type_helpers.rb +1 -1
- data/spec/support/versioned_helpers.rb +3 -3
- metadata +80 -33
- data/lib/grape/util/deep_merge.rb +0 -23
- data/lib/grape/util/hash_stack.rb +0 -120
- data/lib/grape/validations/at_least_one_of.rb +0 -25
- data/lib/grape/validations/exactly_one_of.rb +0 -26
- data/lib/grape/validations/mutual_exclusion.rb +0 -25
- data/lib/grape/validations/regexp.rb +0 -12
- data/lib/grape/validations/values.rb +0 -23
- data/spec/grape/util/hash_stack_spec.rb +0 -132
@@ -9,7 +9,7 @@ describe Grape::Middleware::Auth::Strategies do
|
|
9
9
|
Rack::Builder.new do |b|
|
10
10
|
b.use Grape::Middleware::Error
|
11
11
|
b.use(Grape::Middleware::Auth::Base, type: :http_basic, proc: proc)
|
12
|
-
b.run lambda { |env| [200, {}, [
|
12
|
+
b.run lambda { |env| [200, {}, ['Hello there.']] }
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -34,8 +34,8 @@ describe Grape::Middleware::Auth::Strategies do
|
|
34
34
|
RSpec::Matchers.define :be_challenge do
|
35
35
|
match do |actual_response|
|
36
36
|
actual_response.status == 401 &&
|
37
|
-
|
38
|
-
|
37
|
+
actual_response['WWW-Authenticate'] =~ /^Digest / &&
|
38
|
+
actual_response.body.empty?
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -66,16 +66,15 @@ describe Grape::Middleware::Auth::Strategies do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'authenticates if given valid creds' do
|
69
|
-
digest_authorize
|
69
|
+
digest_authorize 'foo', 'bar'
|
70
70
|
get '/test'
|
71
71
|
expect(last_response.status).to eq(200)
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'throws a 401 if given invalid creds' do
|
75
|
-
digest_authorize
|
75
|
+
digest_authorize 'bar', 'foo'
|
76
76
|
get '/test'
|
77
77
|
expect(last_response.status).to eq(401)
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
81
80
|
end
|
@@ -2,12 +2,11 @@ require 'spec_helper'
|
|
2
2
|
require 'active_support/core_ext/hash'
|
3
3
|
|
4
4
|
describe Grape::Middleware::Error do
|
5
|
-
|
6
5
|
# raises a text exception
|
7
6
|
class ExceptionApp
|
8
7
|
class << self
|
9
8
|
def call(env)
|
10
|
-
|
9
|
+
fail 'rain!'
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -16,11 +15,11 @@ describe Grape::Middleware::Error do
|
|
16
15
|
class ErrorHashApp
|
17
16
|
class << self
|
18
17
|
def error!(message, status)
|
19
|
-
throw :error, message: { error: message, detail:
|
18
|
+
throw :error, message: { error: message, detail: 'missing widget' }, status: status
|
20
19
|
end
|
21
20
|
|
22
21
|
def call(env)
|
23
|
-
error!(
|
22
|
+
error!('rain!', 401)
|
24
23
|
end
|
25
24
|
end
|
26
25
|
end
|
@@ -33,7 +32,7 @@ describe Grape::Middleware::Error do
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def call(env)
|
36
|
-
error!(
|
35
|
+
error!('Access Denied', 401)
|
37
36
|
end
|
38
37
|
end
|
39
38
|
end
|
@@ -45,7 +44,7 @@ describe Grape::Middleware::Error do
|
|
45
44
|
class CustomErrorApp
|
46
45
|
class << self
|
47
46
|
def call(env)
|
48
|
-
|
47
|
+
fail CustomError, status: 400, message: 'failed validation'
|
49
48
|
end
|
50
49
|
end
|
51
50
|
end
|
@@ -69,7 +68,7 @@ describe Grape::Middleware::Error do
|
|
69
68
|
run ExceptionApp
|
70
69
|
end
|
71
70
|
get '/'
|
72
|
-
expect(last_response.body).to eq(
|
71
|
+
expect(last_response.body).to eq('rain!')
|
73
72
|
end
|
74
73
|
|
75
74
|
it 'defaults to a 500 status' do
|
@@ -161,9 +160,9 @@ describe Grape::Middleware::Error do
|
|
161
160
|
use Grape::Middleware::Error, rescue_all: true,
|
162
161
|
format: :custom,
|
163
162
|
error_formatters: {
|
164
|
-
custom: lambda
|
163
|
+
custom: lambda do |message, backtrace, options, env|
|
165
164
|
{ custom_formatter: message }.inspect
|
166
|
-
|
165
|
+
end
|
167
166
|
}
|
168
167
|
run ExceptionApp
|
169
168
|
end
|
@@ -192,6 +191,5 @@ describe Grape::Middleware::Error do
|
|
192
191
|
expect(last_response.status).to eq(400)
|
193
192
|
expect(last_response.body).to eq('failed validation')
|
194
193
|
end
|
195
|
-
|
196
194
|
end
|
197
195
|
end
|
@@ -4,11 +4,11 @@ describe Grape::Middleware::Formatter do
|
|
4
4
|
subject { Grape::Middleware::Formatter.new(app) }
|
5
5
|
before { allow(subject).to receive(:dup).and_return(subject) }
|
6
6
|
|
7
|
-
let(:app) { lambda { |env| [200, {}, [@body || {
|
7
|
+
let(:app) { lambda { |env| [200, {}, [@body || { 'foo' => 'bar' }]] } }
|
8
8
|
|
9
9
|
context 'serialization' do
|
10
10
|
it 'looks at the bodies for possibly serializable data' do
|
11
|
-
@body = {
|
11
|
+
@body = { 'abc' => 'def' }
|
12
12
|
_, _, bodies = *subject.call('PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json')
|
13
13
|
bodies.each { |b| expect(b).to eq(MultiJson.dump(@body)) }
|
14
14
|
end
|
@@ -36,10 +36,10 @@ describe Grape::Middleware::Formatter do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'calls #to_xml if the content type is xml' do
|
39
|
-
@body =
|
39
|
+
@body = 'string'
|
40
40
|
@body.instance_eval do
|
41
41
|
def to_xml
|
42
|
-
|
42
|
+
'<bar/>'
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -54,24 +54,23 @@ describe Grape::Middleware::Formatter do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'rescues formatter-specific exceptions' do
|
57
|
-
allow(formatter).to receive(:call) {
|
57
|
+
allow(formatter).to receive(:call) { fail Grape::Exceptions::InvalidFormatter.new(String, 'xml') }
|
58
58
|
|
59
|
-
expect
|
59
|
+
expect do
|
60
60
|
catch(:error) { subject.call('PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
|
61
|
-
|
61
|
+
end.to_not raise_error
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'does not rescue other exceptions' do
|
65
|
-
allow(formatter).to receive(:call) {
|
65
|
+
allow(formatter).to receive(:call) { fail StandardError }
|
66
66
|
|
67
|
-
expect
|
67
|
+
expect do
|
68
68
|
catch(:error) { subject.call('PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
|
69
|
-
|
69
|
+
end.to raise_error
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
context 'detection' do
|
74
|
-
|
75
74
|
it 'uses the xml extension if one is provided' do
|
76
75
|
subject.call('PATH_INFO' => '/info.xml')
|
77
76
|
expect(subject.env['api.format']).to eq(:xml)
|
@@ -186,8 +185,8 @@ describe Grape::Middleware::Formatter do
|
|
186
185
|
end
|
187
186
|
|
188
187
|
context 'input' do
|
189
|
-
|
190
|
-
[
|
188
|
+
%w(POST PATCH PUT DELETE).each do |method|
|
189
|
+
['application/json', 'application/json; charset=utf-8'].each do |content_type|
|
191
190
|
context content_type do
|
192
191
|
it 'parses the body from #{method} and copies values into rack.request.form_hash' do
|
193
192
|
io = StringIO.new('{"is_boolean":true,"string":"thing"}')
|
@@ -215,7 +214,7 @@ describe Grape::Middleware::Formatter do
|
|
215
214
|
expect(subject.env['rack.request.form_hash']['is_boolean']).to be true
|
216
215
|
expect(subject.env['rack.request.form_hash']['string']).to eq('thing')
|
217
216
|
end
|
218
|
-
it
|
217
|
+
it 'rewinds IO' do
|
219
218
|
io = StringIO.new('{"is_boolean":true,"string":"thing"}')
|
220
219
|
io.read
|
221
220
|
subject.call(
|
@@ -254,5 +253,4 @@ describe Grape::Middleware::Formatter do
|
|
254
253
|
end
|
255
254
|
end
|
256
255
|
end
|
257
|
-
|
258
256
|
end
|
@@ -30,9 +30,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'fails with 406 Not Acceptable if version is not supported' do
|
33
|
-
expect
|
33
|
+
expect do
|
34
34
|
subject.call('HTTP_ACCEPT_VERSION' => 'v2').last
|
35
|
-
|
35
|
+
end.to throw_symbol(
|
36
36
|
:error,
|
37
37
|
status: 406,
|
38
38
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -59,9 +59,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'fails with 406 Not Acceptable if header is not set' do
|
62
|
-
expect
|
62
|
+
expect do
|
63
63
|
subject.call({}).last
|
64
|
-
|
64
|
+
end.to throw_symbol(
|
65
65
|
:error,
|
66
66
|
status: 406,
|
67
67
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -70,9 +70,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'fails with 406 Not Acceptable if header is empty' do
|
73
|
-
expect
|
73
|
+
expect do
|
74
74
|
subject.call('HTTP_ACCEPT_VERSION' => '').last
|
75
|
-
|
75
|
+
end.to throw_symbol(
|
76
76
|
:error,
|
77
77
|
status: 406,
|
78
78
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -93,9 +93,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
|
93
93
|
end
|
94
94
|
|
95
95
|
it 'fails with 406 Not Acceptable if header is not set' do
|
96
|
-
expect
|
96
|
+
expect do
|
97
97
|
subject.call({}).last
|
98
|
-
|
98
|
+
end.to throw_symbol(
|
99
99
|
:error,
|
100
100
|
status: 406,
|
101
101
|
headers: {},
|
@@ -104,9 +104,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'fails with 406 Not Acceptable if header is empty' do
|
107
|
-
expect
|
107
|
+
expect do
|
108
108
|
subject.call('HTTP_ACCEPT_VERSION' => '').last
|
109
|
-
|
109
|
+
end.to throw_symbol(
|
110
110
|
:error,
|
111
111
|
status: 406,
|
112
112
|
headers: {},
|
@@ -84,9 +84,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
87
|
-
expect
|
87
|
+
expect do
|
88
88
|
subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor+json').last
|
89
|
-
|
89
|
+
end.to throw_symbol(
|
90
90
|
:error,
|
91
91
|
status: 406,
|
92
92
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -112,9 +112,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
112
112
|
end
|
113
113
|
|
114
114
|
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
115
|
-
expect
|
115
|
+
expect do
|
116
116
|
subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor-v1+json').last
|
117
|
-
|
117
|
+
end.to throw_symbol(
|
118
118
|
:error,
|
119
119
|
status: 406,
|
120
120
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -142,9 +142,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
142
142
|
end
|
143
143
|
|
144
144
|
it 'fails with 406 Not Acceptable if version is invalid' do
|
145
|
-
expect
|
145
|
+
expect do
|
146
146
|
subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last
|
147
|
-
|
147
|
+
end.to throw_symbol(
|
148
148
|
:error,
|
149
149
|
status: 406,
|
150
150
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -171,9 +171,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
171
171
|
end
|
172
172
|
|
173
173
|
it 'fails with 406 Not Acceptable if header is not set' do
|
174
|
-
expect
|
174
|
+
expect do
|
175
175
|
subject.call({}).last
|
176
|
-
|
176
|
+
end.to throw_symbol(
|
177
177
|
:error,
|
178
178
|
status: 406,
|
179
179
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -182,9 +182,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
182
182
|
end
|
183
183
|
|
184
184
|
it 'fails with 406 Not Acceptable if header is empty' do
|
185
|
-
expect
|
185
|
+
expect do
|
186
186
|
subject.call('HTTP_ACCEPT' => '').last
|
187
|
-
|
187
|
+
end.to throw_symbol(
|
188
188
|
:error,
|
189
189
|
status: 406,
|
190
190
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -193,9 +193,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
193
193
|
end
|
194
194
|
|
195
195
|
it 'fails with 406 Not Acceptable if type is a range' do
|
196
|
-
expect
|
196
|
+
expect do
|
197
197
|
subject.call('HTTP_ACCEPT' => '*/*').last
|
198
|
-
|
198
|
+
end.to throw_symbol(
|
199
199
|
:error,
|
200
200
|
status: 406,
|
201
201
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -204,9 +204,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
204
204
|
end
|
205
205
|
|
206
206
|
it 'fails with 406 Not Acceptable if subtype is a range' do
|
207
|
-
expect
|
207
|
+
expect do
|
208
208
|
subject.call('HTTP_ACCEPT' => 'application/*').last
|
209
|
-
|
209
|
+
end.to throw_symbol(
|
210
210
|
:error,
|
211
211
|
status: 406,
|
212
212
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -227,9 +227,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
227
227
|
end
|
228
228
|
|
229
229
|
it 'fails with 406 Not Acceptable if header is not set' do
|
230
|
-
expect
|
230
|
+
expect do
|
231
231
|
subject.call({}).last
|
232
|
-
|
232
|
+
end.to throw_symbol(
|
233
233
|
:error,
|
234
234
|
status: 406,
|
235
235
|
headers: {},
|
@@ -238,9 +238,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
238
238
|
end
|
239
239
|
|
240
240
|
it 'fails with 406 Not Acceptable if header is empty' do
|
241
|
-
expect
|
241
|
+
expect do
|
242
242
|
subject.call('HTTP_ACCEPT' => '').last
|
243
|
-
|
243
|
+
end.to throw_symbol(
|
244
244
|
:error,
|
245
245
|
status: 406,
|
246
246
|
headers: {},
|
@@ -249,9 +249,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
249
249
|
end
|
250
250
|
|
251
251
|
it 'fails with 406 Not Acceptable if type is a range' do
|
252
|
-
expect
|
252
|
+
expect do
|
253
253
|
subject.call('HTTP_ACCEPT' => '*/*').last
|
254
|
-
|
254
|
+
end.to throw_symbol(
|
255
255
|
:error,
|
256
256
|
status: 406,
|
257
257
|
headers: {},
|
@@ -260,9 +260,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
260
260
|
end
|
261
261
|
|
262
262
|
it 'fails with 406 Not Acceptable if subtype is a range' do
|
263
|
-
expect
|
263
|
+
expect do
|
264
264
|
subject.call('HTTP_ACCEPT' => 'application/*').last
|
265
|
-
|
265
|
+
end.to throw_symbol(
|
266
266
|
:error,
|
267
267
|
status: 406,
|
268
268
|
headers: {},
|
@@ -277,7 +277,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
277
277
|
|
278
278
|
context 'when multiple versions are specified' do
|
279
279
|
before do
|
280
|
-
@options[:versions] =
|
280
|
+
@options[:versions] = %w(v1 v2)
|
281
281
|
end
|
282
282
|
|
283
283
|
it 'succeeds with v1' do
|
@@ -289,9 +289,9 @@ describe Grape::Middleware::Versioner::Header do
|
|
289
289
|
end
|
290
290
|
|
291
291
|
it 'fails with another version' do
|
292
|
-
expect
|
292
|
+
expect do
|
293
293
|
subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json')
|
294
|
-
|
294
|
+
end.to throw_symbol(
|
295
295
|
:error,
|
296
296
|
status: 406,
|
297
297
|
headers: { 'X-Cascade' => 'pass' },
|
@@ -1,48 +1,47 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Grape::Middleware::Versioner::Param do
|
4
|
-
|
5
4
|
let(:app) { lambda { |env| [200, env, env['api.version']] } }
|
6
5
|
subject { Grape::Middleware::Versioner::Param.new(app, @options || {}) }
|
7
6
|
|
8
7
|
it 'sets the API version based on the default param (apiver)' do
|
9
|
-
env = Rack::MockRequest.env_for(
|
10
|
-
expect(subject.call(env)[1][
|
8
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
9
|
+
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
11
10
|
end
|
12
11
|
|
13
12
|
it 'cuts (only) the version out of the params' do
|
14
|
-
env = Rack::MockRequest.env_for(
|
13
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1', 'other_param' => '5' })
|
15
14
|
env['rack.request.query_hash'] = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
16
|
-
expect(subject.call(env)[1]['rack.request.query_hash'][
|
17
|
-
expect(subject.call(env)[1]['rack.request.query_hash'][
|
15
|
+
expect(subject.call(env)[1]['rack.request.query_hash']['apiver']).to be_nil
|
16
|
+
expect(subject.call(env)[1]['rack.request.query_hash']['other_param']).to eq('5')
|
18
17
|
end
|
19
18
|
|
20
19
|
it 'provides a nil version if no version is given' do
|
21
|
-
env = Rack::MockRequest.env_for(
|
20
|
+
env = Rack::MockRequest.env_for('/')
|
22
21
|
expect(subject.call(env).last).to be_nil
|
23
22
|
end
|
24
23
|
|
25
24
|
context 'with specified parameter name' do
|
26
25
|
before { @options = { parameter: 'v' } }
|
27
26
|
it 'sets the API version based on the custom parameter name' do
|
28
|
-
env = Rack::MockRequest.env_for(
|
29
|
-
expect(subject.call(env)[1][
|
27
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
|
28
|
+
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
30
29
|
end
|
31
30
|
it 'does not set the API version based on the default param' do
|
32
|
-
env = Rack::MockRequest.env_for(
|
33
|
-
expect(subject.call(env)[1][
|
31
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
32
|
+
expect(subject.call(env)[1]['api.version']).to be_nil
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
36
|
context 'with specified versions' do
|
38
|
-
before { @options = { versions:
|
37
|
+
before { @options = { versions: %w(v1 v2) } }
|
39
38
|
it 'throws an error if a non-allowed version is specified' do
|
40
|
-
env = Rack::MockRequest.env_for(
|
39
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
|
41
40
|
expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
|
42
41
|
end
|
43
42
|
it 'allows versions that have been specified' do
|
44
|
-
env = Rack::MockRequest.env_for(
|
45
|
-
expect(subject.call(env)[1][
|
43
|
+
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
44
|
+
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -51,8 +50,7 @@ describe Grape::Middleware::Versioner::Param do
|
|
51
50
|
versions: ['v1'],
|
52
51
|
version_options: { using: :header }
|
53
52
|
}
|
54
|
-
env = Rack::MockRequest.env_for(
|
53
|
+
env = Rack::MockRequest.env_for('/awesome', params: {})
|
55
54
|
expect(subject.call(env).first).to eq(200)
|
56
55
|
end
|
57
|
-
|
58
56
|
end
|