grape 1.1.0 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -43
- data/LICENSE +1 -1
- data/README.md +394 -47
- data/UPGRADING.md +111 -0
- data/grape.gemspec +3 -1
- data/lib/grape.rb +98 -66
- data/lib/grape/api.rb +136 -175
- data/lib/grape/api/instance.rb +280 -0
- data/lib/grape/config.rb +32 -0
- data/lib/grape/dsl/callbacks.rb +20 -0
- data/lib/grape/dsl/desc.rb +39 -7
- data/lib/grape/dsl/inside_route.rb +12 -6
- data/lib/grape/dsl/middleware.rb +7 -0
- data/lib/grape/dsl/parameters.rb +9 -4
- data/lib/grape/dsl/routing.rb +5 -1
- data/lib/grape/dsl/validations.rb +4 -3
- data/lib/grape/eager_load.rb +18 -0
- data/lib/grape/endpoint.rb +42 -26
- data/lib/grape/error_formatter.rb +1 -1
- data/lib/grape/exceptions/base.rb +9 -1
- data/lib/grape/exceptions/invalid_response.rb +9 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -2
- data/lib/grape/formatter.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/base.rb +2 -4
- data/lib/grape/middleware/base.rb +2 -0
- data/lib/grape/middleware/error.rb +9 -4
- data/lib/grape/middleware/helpers.rb +10 -0
- data/lib/grape/middleware/stack.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +4 -4
- data/lib/grape/parser.rb +1 -1
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router/attribute_translator.rb +2 -0
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/util/base_inheritable.rb +34 -0
- data/lib/grape/util/endpoint_configuration.rb +6 -0
- data/lib/grape/util/inheritable_values.rb +5 -25
- data/lib/grape/util/lazy_block.rb +25 -0
- data/lib/grape/util/lazy_value.rb +95 -0
- data/lib/grape/util/reverse_stackable_values.rb +7 -36
- data/lib/grape/util/stackable_values.rb +19 -22
- data/lib/grape/validations/attributes_iterator.rb +5 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +11 -0
- data/lib/grape/validations/params_scope.rb +20 -14
- data/lib/grape/validations/single_attribute_iterator.rb +13 -0
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -1
- data/lib/grape/validations/types/file.rb +1 -1
- data/lib/grape/validations/validator_factory.rb +6 -11
- data/lib/grape/validations/validators/all_or_none.rb +6 -13
- data/lib/grape/validations/validators/as.rb +2 -3
- data/lib/grape/validations/validators/at_least_one_of.rb +5 -13
- data/lib/grape/validations/validators/base.rb +11 -10
- data/lib/grape/validations/validators/coerce.rb +4 -0
- data/lib/grape/validations/validators/default.rb +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -23
- data/lib/grape/validations/validators/multiple_params_base.rb +14 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +6 -18
- data/lib/grape/validations/validators/same_as.rb +23 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/defines_boolean_in_params_spec.rb +37 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +59 -0
- data/spec/grape/api_remount_spec.rb +466 -0
- data/spec/grape/api_spec.rb +379 -1
- data/spec/grape/config_spec.rb +17 -0
- data/spec/grape/dsl/desc_spec.rb +40 -16
- data/spec/grape/dsl/middleware_spec.rb +8 -0
- data/spec/grape/dsl/routing_spec.rb +10 -0
- data/spec/grape/endpoint_spec.rb +40 -4
- data/spec/grape/exceptions/base_spec.rb +65 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +11 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +6 -4
- data/spec/grape/integration/rack_spec.rb +22 -6
- data/spec/grape/middleware/auth/dsl_spec.rb +3 -3
- data/spec/grape/middleware/base_spec.rb +8 -0
- data/spec/grape/middleware/exception_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +15 -5
- data/spec/grape/middleware/versioner/header_spec.rb +6 -0
- data/spec/grape/named_api_spec.rb +19 -0
- data/spec/grape/request_spec.rb +24 -0
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +29 -0
- data/spec/grape/validations/params_scope_spec.rb +184 -8
- data/spec/grape/validations/single_attribute_iterator_spec.rb +33 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +138 -30
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +173 -29
- data/spec/grape/validations/validators/coerce_spec.rb +10 -2
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +202 -38
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +184 -27
- data/spec/grape/validations/validators/same_as_spec.rb +63 -0
- data/spec/grape/validations_spec.rb +33 -21
- data/spec/spec_helper.rb +4 -1
- metadata +35 -23
- data/Appraisals +0 -32
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile +0 -35
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_edge.gemfile +0 -35
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
data/spec/grape/dsl/desc_spec.rb
CHANGED
@@ -21,36 +21,60 @@ module Grape
|
|
21
21
|
|
22
22
|
it 'can be set with a block' do
|
23
23
|
expected_options = {
|
24
|
+
summary: 'summary',
|
24
25
|
description: 'The description',
|
25
26
|
detail: 'more details',
|
26
27
|
params: { first: :param },
|
27
28
|
entity: Object,
|
28
29
|
http_codes: [[401, 'Unauthorized', 'Entities::Error']],
|
29
30
|
named: 'My named route',
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
body_name: 'My body name',
|
32
|
+
headers: [
|
33
|
+
XAuthToken: {
|
34
|
+
description: 'Valdates your identity',
|
35
|
+
required: true
|
36
|
+
},
|
37
|
+
XOptionalHeader: {
|
38
|
+
description: 'Not really needed',
|
39
|
+
required: false
|
40
|
+
}
|
41
|
+
],
|
42
|
+
hidden: false,
|
43
|
+
deprecated: false,
|
44
|
+
is_array: true,
|
45
|
+
nickname: 'nickname',
|
46
|
+
produces: %w[array of mime_types],
|
47
|
+
consumes: %w[array of mime_types],
|
48
|
+
tags: %w[tag1 tag2],
|
49
|
+
security: %w[array of security schemes]
|
38
50
|
}
|
39
51
|
|
40
52
|
subject.desc 'The description' do
|
53
|
+
summary 'summary'
|
41
54
|
detail 'more details'
|
42
55
|
params(first: :param)
|
43
56
|
success Object
|
44
57
|
failure [[401, 'Unauthorized', 'Entities::Error']]
|
45
58
|
named 'My named route'
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
body_name 'My body name'
|
60
|
+
headers [
|
61
|
+
XAuthToken: {
|
62
|
+
description: 'Valdates your identity',
|
63
|
+
required: true
|
64
|
+
},
|
65
|
+
XOptionalHeader: {
|
66
|
+
description: 'Not really needed',
|
67
|
+
required: false
|
68
|
+
}
|
69
|
+
]
|
70
|
+
hidden false
|
71
|
+
deprecated false
|
72
|
+
is_array true
|
73
|
+
nickname 'nickname'
|
74
|
+
produces %w[array of mime_types]
|
75
|
+
consumes %w[array of mime_types]
|
76
|
+
tags %w[tag1 tag2]
|
77
|
+
security %w[array of security schemes]
|
54
78
|
end
|
55
79
|
|
56
80
|
expect(subject.namespace_setting(:description)).to eq(expected_options)
|
@@ -22,6 +22,14 @@ module Grape
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
describe '.insert' do
|
26
|
+
it 'adds a middleware with the right operation' do
|
27
|
+
expect(subject).to receive(:namespace_stackable).with(:middleware, [:insert, 0, :arg1, proc])
|
28
|
+
|
29
|
+
subject.insert 0, :arg1, &proc
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
25
33
|
describe '.insert_before' do
|
26
34
|
it 'adds a middleware with the right operation' do
|
27
35
|
expect(subject).to receive(:namespace_stackable).with(:middleware, [:insert_before, foo_middleware, :arg1, proc])
|
@@ -70,6 +70,16 @@ module Grape
|
|
70
70
|
|
71
71
|
expect(app2.inheritable_setting.to_hash[:namespace_stackable]).to eq(mount_path: ['/app1', '/app2'])
|
72
72
|
end
|
73
|
+
|
74
|
+
it 'mounts multiple routes at once' do
|
75
|
+
base_app = Class.new(Grape::API)
|
76
|
+
app1 = Class.new(Grape::API)
|
77
|
+
app2 = Class.new(Grape::API)
|
78
|
+
base_app.mount(app1 => '/app1', app2 => '/app2')
|
79
|
+
|
80
|
+
expect(app1.inheritable_setting.to_hash[:namespace_stackable]).to eq(mount_path: ['/app1'])
|
81
|
+
expect(app2.inheritable_setting.to_hash[:namespace_stackable]).to eq(mount_path: ['/app2'])
|
82
|
+
end
|
73
83
|
end
|
74
84
|
|
75
85
|
describe '.route' do
|
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Grape::Endpoint do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '.before_each' do
|
11
|
-
after { Grape::Endpoint.before_each
|
11
|
+
after { Grape::Endpoint.before_each.clear }
|
12
12
|
|
13
13
|
it 'is settable via block' do
|
14
14
|
block = ->(_endpoint) { 'noop' }
|
@@ -472,12 +472,12 @@ describe Grape::Endpoint do
|
|
472
472
|
expect(last_response.status).to eq(200)
|
473
473
|
end
|
474
474
|
|
475
|
-
it 'does not include
|
475
|
+
it 'does not include renamed missing attributes if that option is passed' do
|
476
476
|
subject.params do
|
477
|
-
optional :
|
477
|
+
optional :renamed_original, as: :renamed
|
478
478
|
end
|
479
479
|
subject.get '/declared' do
|
480
|
-
error! 'expected nil', 400 if declared(params, include_missing: false).key?(:
|
480
|
+
error! 'expected nil', 400 if declared(params, include_missing: false).key?(:renamed)
|
481
481
|
''
|
482
482
|
end
|
483
483
|
|
@@ -1089,6 +1089,36 @@ describe Grape::Endpoint do
|
|
1089
1089
|
expect(last_response.headers['X-Custom']).to eq('value')
|
1090
1090
|
end
|
1091
1091
|
|
1092
|
+
it 'merges additional headers with headers set before call' do
|
1093
|
+
subject.before do
|
1094
|
+
header 'X-Before-Test', 'before-sample'
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
subject.get '/hey' do
|
1098
|
+
header 'X-Test', 'test-sample'
|
1099
|
+
error!({ 'dude' => 'rad' }, 403, 'X-Error' => 'error')
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
get '/hey.json'
|
1103
|
+
expect(last_response.headers['X-Before-Test']).to eq('before-sample')
|
1104
|
+
expect(last_response.headers['X-Test']).to eq('test-sample')
|
1105
|
+
expect(last_response.headers['X-Error']).to eq('error')
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
it 'does not merges additional headers with headers set after call' do
|
1109
|
+
subject.after do
|
1110
|
+
header 'X-After-Test', 'after-sample'
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
subject.get '/hey' do
|
1114
|
+
error!({ 'dude' => 'rad' }, 403, 'X-Error' => 'error')
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
get '/hey.json'
|
1118
|
+
expect(last_response.headers['X-Error']).to eq('error')
|
1119
|
+
expect(last_response.headers['X-After-Test']).to be_nil
|
1120
|
+
end
|
1121
|
+
|
1092
1122
|
it 'sets the status code for the endpoint' do
|
1093
1123
|
memoized_endpoint = nil
|
1094
1124
|
|
@@ -1492,6 +1522,9 @@ describe Grape::Endpoint do
|
|
1492
1522
|
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
|
1493
1523
|
filters: [],
|
1494
1524
|
type: :after }),
|
1525
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
|
1526
|
+
filters: [],
|
1527
|
+
type: :finally }),
|
1495
1528
|
have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
|
1496
1529
|
env: an_instance_of(Hash) }),
|
1497
1530
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
@@ -1518,6 +1551,9 @@ describe Grape::Endpoint do
|
|
1518
1551
|
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
|
1519
1552
|
filters: [],
|
1520
1553
|
type: :after }),
|
1554
|
+
have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
|
1555
|
+
filters: [],
|
1556
|
+
type: :finally }),
|
1521
1557
|
have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
|
1522
1558
|
formatter: a_kind_of(Module) })
|
1523
1559
|
)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Exceptions::Base do
|
4
|
+
describe '#compose_message' do
|
5
|
+
subject { described_class.new.send(:compose_message, key, attributes) }
|
6
|
+
|
7
|
+
let(:key) { :invalid_formatter }
|
8
|
+
let(:attributes) { { klass: String, to_format: 'xml' } }
|
9
|
+
|
10
|
+
after do
|
11
|
+
I18n.enforce_available_locales = true
|
12
|
+
I18n.available_locales = %i[en]
|
13
|
+
I18n.locale = :en
|
14
|
+
I18n.default_locale = :en
|
15
|
+
I18n.reload!
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when I18n enforces available locales' do
|
19
|
+
before { I18n.enforce_available_locales = true }
|
20
|
+
|
21
|
+
context 'when the fallback locale is available' do
|
22
|
+
before do
|
23
|
+
I18n.available_locales = %i[de en]
|
24
|
+
I18n.default_locale = :de
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns the translated message' do
|
28
|
+
expect(subject).to eq('cannot convert String to xml')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the fallback locale is not available' do
|
33
|
+
before do
|
34
|
+
I18n.available_locales = %i[de jp]
|
35
|
+
I18n.locale = :de
|
36
|
+
I18n.default_locale = :de
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns the translation string' do
|
40
|
+
expect(subject).to eq("grape.errors.messages.#{key}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when I18n does not enforce available locales' do
|
46
|
+
before { I18n.enforce_available_locales = false }
|
47
|
+
|
48
|
+
context 'when the fallback locale is available' do
|
49
|
+
before { I18n.available_locales = %i[de en] }
|
50
|
+
|
51
|
+
it 'returns the translated message' do
|
52
|
+
expect(subject).to eq('cannot convert String to xml')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the fallback locale is not available' do
|
57
|
+
before { I18n.available_locales = %i[de jp] }
|
58
|
+
|
59
|
+
it 'returns the translated message' do
|
60
|
+
expect(subject).to eq('cannot convert String to xml')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -77,10 +77,12 @@ describe Grape::Exceptions::ValidationErrors do
|
|
77
77
|
end
|
78
78
|
get '/exactly_one_of', beer: 'string', wine: 'anotherstring'
|
79
79
|
expect(last_response.status).to eq(400)
|
80
|
-
expect(JSON.parse(last_response.body)).to eq(
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
expect(JSON.parse(last_response.body)).to eq(
|
81
|
+
[
|
82
|
+
'params' => %w[beer wine juice],
|
83
|
+
'messages' => ['are missing, exactly one parameter must be provided']
|
84
|
+
]
|
85
|
+
)
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end
|
@@ -19,16 +19,32 @@ describe Rack do
|
|
19
19
|
}
|
20
20
|
env = Rack::MockRequest.env_for('/', options)
|
21
21
|
|
22
|
-
unless RUBY_PLATFORM == 'java'
|
23
|
-
major, minor, patch = Rack.release.split('.').map(&:to_i)
|
24
|
-
patch ||= 0 # rack <= 1.5.2 does not specify patch version
|
25
|
-
pending 'Rack 1.5.3 or 1.6.1 required' unless major >= 2 || (major >= 1 && ((minor == 5 && patch >= 3) || (minor >= 6)))
|
26
|
-
end
|
27
|
-
|
28
22
|
expect(JSON.parse(app.call(env)[2].body.first)['params_keys']).to match_array('test')
|
29
23
|
ensure
|
30
24
|
input.close
|
31
25
|
input.unlink
|
32
26
|
end
|
33
27
|
end
|
28
|
+
|
29
|
+
context 'when the app is mounted' do
|
30
|
+
def app
|
31
|
+
@main_app ||= Class.new(Grape::API) do
|
32
|
+
get 'ping'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let!(:base) do
|
37
|
+
app_to_mount = app
|
38
|
+
Class.new(Grape::API) do
|
39
|
+
namespace 'namespace' do
|
40
|
+
mount app_to_mount
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'finds the app on the namespace' do
|
46
|
+
get '/namespace/ping'
|
47
|
+
expect(last_response.status).to eq 200
|
48
|
+
end
|
49
|
+
end
|
34
50
|
end
|
@@ -15,15 +15,15 @@ describe Grape::Middleware::Auth::DSL do
|
|
15
15
|
|
16
16
|
describe '.auth' do
|
17
17
|
it 'stets auth parameters' do
|
18
|
-
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
18
|
+
expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
19
19
|
|
20
20
|
subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
|
21
21
|
expect(subject.auth).to eq(settings)
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'can be called multiple times' do
|
25
|
-
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
26
|
-
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings.merge(realm: 'super_secret'))
|
25
|
+
expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
26
|
+
expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings.merge(realm: 'super_secret'))
|
27
27
|
|
28
28
|
subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
|
29
29
|
first_settings = subject.auth
|
@@ -114,6 +114,14 @@ describe Grape::Middleware::Base do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
+
describe '#context' do
|
118
|
+
subject { Grape::Middleware::Base.new(blank_app) }
|
119
|
+
it 'allows access to response context' do
|
120
|
+
subject.call(Grape::Env::API_ENDPOINT => { header: 'some header' })
|
121
|
+
expect(subject.context).to eq(header: 'some header')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
117
125
|
context 'options' do
|
118
126
|
it 'persists options passed at initialization' do
|
119
127
|
expect(Grape::Middleware::Base.new(blank_app, abc: true).options[:abc]).to be true
|
@@ -128,7 +128,7 @@ describe Grape::Middleware::Error do
|
|
128
128
|
subject do
|
129
129
|
Rack::Builder.app do
|
130
130
|
use Spec::Support::EndpointFaker
|
131
|
-
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> {
|
131
|
+
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { Rack::Response.new('rescued', 200, {}) } }
|
132
132
|
run ExceptionSpec::OtherExceptionApp
|
133
133
|
end
|
134
134
|
end
|
@@ -213,7 +213,13 @@ describe Grape::Middleware::Formatter do
|
|
213
213
|
context 'no content responses' do
|
214
214
|
let(:no_content_response) { ->(status) { [status, {}, ['']] } }
|
215
215
|
|
216
|
-
|
216
|
+
STATUSES_WITHOUT_BODY = if Gem::Version.new(Rack.release) >= Gem::Version.new('2.1.0')
|
217
|
+
Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.keys
|
218
|
+
else
|
219
|
+
Rack::Utils::STATUS_WITH_NO_ENTITY_BODY
|
220
|
+
end
|
221
|
+
|
222
|
+
STATUSES_WITHOUT_BODY.each do |status|
|
217
223
|
it "does not modify a #{status} response" do
|
218
224
|
expected_response = no_content_response[status]
|
219
225
|
allow(app).to receive(:call).and_return(expected_response)
|
@@ -247,7 +253,7 @@ describe Grape::Middleware::Formatter do
|
|
247
253
|
let(:content_type) { 'application/atom+xml' }
|
248
254
|
|
249
255
|
it 'returns a 415 HTTP error status' do
|
250
|
-
error = catch(:error)
|
256
|
+
error = catch(:error) do
|
251
257
|
subject.call(
|
252
258
|
'PATH_INFO' => '/info',
|
253
259
|
'REQUEST_METHOD' => method,
|
@@ -255,7 +261,7 @@ describe Grape::Middleware::Formatter do
|
|
255
261
|
'rack.input' => io,
|
256
262
|
'CONTENT_LENGTH' => io.length
|
257
263
|
)
|
258
|
-
|
264
|
+
end
|
259
265
|
expect(error[:status]).to eq(415)
|
260
266
|
expect(error[:message]).to eq("The provided content-type 'application/atom+xml' is not supported.")
|
261
267
|
end
|
@@ -391,6 +397,10 @@ describe Grape::Middleware::Formatter do
|
|
391
397
|
Grape::Formatter.register :invalid, InvalidFormatter
|
392
398
|
Grape::ContentTypes::CONTENT_TYPES[:invalid] = 'application/x-invalid'
|
393
399
|
end
|
400
|
+
after do
|
401
|
+
Grape::ContentTypes::CONTENT_TYPES.delete(:invalid)
|
402
|
+
Grape::Formatter.default_elements.delete(:invalid)
|
403
|
+
end
|
394
404
|
|
395
405
|
it 'returns response by invalid formatter' do
|
396
406
|
env = { 'PATH_INFO' => '/hello.invalid', 'HTTP_ACCEPT' => 'application/x-invalid' }
|
@@ -407,7 +417,7 @@ describe Grape::Middleware::Formatter do
|
|
407
417
|
parsers: { json: ->(_object, _env) { raise StandardError, 'fail' } }
|
408
418
|
)
|
409
419
|
io = StringIO.new('{invalid}')
|
410
|
-
error = catch(:error)
|
420
|
+
error = catch(:error) do
|
411
421
|
subject.call(
|
412
422
|
'PATH_INFO' => '/info',
|
413
423
|
'REQUEST_METHOD' => 'POST',
|
@@ -415,7 +425,7 @@ describe Grape::Middleware::Formatter do
|
|
415
425
|
'rack.input' => io,
|
416
426
|
'CONTENT_LENGTH' => io.length
|
417
427
|
)
|
418
|
-
|
428
|
+
end
|
419
429
|
|
420
430
|
expect(error[:message]).to eq 'fail'
|
421
431
|
expect(error[:backtrace].size).to be >= 1
|
@@ -160,6 +160,12 @@ describe Grape::Middleware::Versioner::Header do
|
|
160
160
|
expect(subject.call({}).first).to eq(200)
|
161
161
|
end
|
162
162
|
|
163
|
+
it 'succeeds if :strict is set to false and given an invalid header' do
|
164
|
+
@options[:version_options][:strict] = false
|
165
|
+
expect(subject.call('HTTP_ACCEPT' => 'yaml').first).to eq(200)
|
166
|
+
expect(subject.call({}).first).to eq(200)
|
167
|
+
end
|
168
|
+
|
163
169
|
context 'when :strict is set' do
|
164
170
|
before do
|
165
171
|
@options[:versions] = ['v1']
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'A named API' do
|
4
|
+
subject(:api_name) { NamedAPI.endpoints.last.options[:for].to_s }
|
5
|
+
|
6
|
+
let(:api) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
get 'test' do
|
9
|
+
'response'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
before { stub_const('NamedAPI', api) }
|
15
|
+
|
16
|
+
it 'can access the name of the API' do
|
17
|
+
expect(api_name).to eq 'NamedAPI'
|
18
|
+
end
|
19
|
+
end
|