grape 1.8.0 → 2.0.0
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 +15 -0
- data/README.md +19 -22
- data/UPGRADING.md +35 -0
- data/grape.gemspec +1 -4
- data/lib/grape/dsl/desc.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +9 -9
- data/lib/grape/endpoint.rb +9 -1
- data/lib/grape/exceptions/missing_group_type.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
- data/lib/grape/http/headers.rb +12 -2
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/error.rb +4 -4
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +8 -2
- data/lib/grape/router/route.rb +1 -1
- data/lib/grape/validations/validators/base.rb +1 -1
- data/lib/grape/validations/validators/values_validator.rb +2 -2
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +15 -2
- metadata +8 -243
- data/spec/grape/api/custom_validations_spec.rb +0 -213
- data/spec/grape/api/deeply_included_options_spec.rb +0 -56
- data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
- data/spec/grape/api/documentation_spec.rb +0 -59
- data/spec/grape/api/inherited_helpers_spec.rb +0 -114
- data/spec/grape/api/instance_spec.rb +0 -103
- data/spec/grape/api/invalid_format_spec.rb +0 -45
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
- data/spec/grape/api/nested_helpers_spec.rb +0 -50
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
- data/spec/grape/api/parameters_modification_spec.rb +0 -41
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
- data/spec/grape/api/recognize_path_spec.rb +0 -21
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
- data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
- data/spec/grape/api/shared_helpers_spec.rb +0 -36
- data/spec/grape/api_remount_spec.rb +0 -509
- data/spec/grape/api_spec.rb +0 -4356
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -98
- data/spec/grape/dsl/headers_spec.rb +0 -62
- data/spec/grape/dsl/helpers_spec.rb +0 -100
- data/spec/grape/dsl/inside_route_spec.rb +0 -531
- data/spec/grape/dsl/logger_spec.rb +0 -24
- data/spec/grape/dsl/middleware_spec.rb +0 -60
- data/spec/grape/dsl/parameters_spec.rb +0 -180
- data/spec/grape/dsl/request_response_spec.rb +0 -225
- data/spec/grape/dsl/routing_spec.rb +0 -275
- data/spec/grape/dsl/settings_spec.rb +0 -261
- data/spec/grape/dsl/validations_spec.rb +0 -55
- data/spec/grape/endpoint/declared_spec.rb +0 -846
- data/spec/grape/endpoint_spec.rb +0 -1085
- data/spec/grape/entity_spec.rb +0 -336
- data/spec/grape/exceptions/base_spec.rb +0 -81
- data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
- data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_option_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
- data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
- data/spec/grape/exceptions/validation_spec.rb +0 -19
- data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
- data/spec/grape/grape_spec.rb +0 -9
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
- data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
- data/spec/grape/integration/rack_spec.rb +0 -51
- data/spec/grape/loading_spec.rb +0 -44
- data/spec/grape/middleware/auth/base_spec.rb +0 -31
- data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
- data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
- data/spec/grape/middleware/base_spec.rb +0 -221
- data/spec/grape/middleware/error_spec.rb +0 -85
- data/spec/grape/middleware/exception_spec.rb +0 -294
- data/spec/grape/middleware/formatter_spec.rb +0 -461
- data/spec/grape/middleware/globals_spec.rb +0 -30
- data/spec/grape/middleware/stack_spec.rb +0 -155
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
- data/spec/grape/middleware/versioner/header_spec.rb +0 -345
- data/spec/grape/middleware/versioner/param_spec.rb +0 -171
- data/spec/grape/middleware/versioner/path_spec.rb +0 -62
- data/spec/grape/middleware/versioner_spec.rb +0 -21
- data/spec/grape/named_api_spec.rb +0 -19
- data/spec/grape/parser_spec.rb +0 -86
- data/spec/grape/path_spec.rb +0 -252
- data/spec/grape/presenters/presenter_spec.rb +0 -71
- data/spec/grape/request_spec.rb +0 -126
- data/spec/grape/util/inheritable_setting_spec.rb +0 -242
- data/spec/grape/util/inheritable_values_spec.rb +0 -79
- data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
- data/spec/grape/util/stackable_values_spec.rb +0 -128
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
- data/spec/grape/validations/attributes_doc_spec.rb +0 -153
- data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
- data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
- data/spec/grape/validations/types_spec.rb +0 -111
- data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
- data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
- data/spec/grape/validations/validators/base_spec.rb +0 -38
- data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
- data/spec/grape/validations/validators/default_spec.rb +0 -463
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
- data/spec/grape/validations/validators/except_values_spec.rb +0 -192
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
- data/spec/grape/validations/validators/presence_spec.rb +0 -315
- data/spec/grape/validations/validators/regexp_spec.rb +0 -161
- data/spec/grape/validations/validators/same_as_spec.rb +0 -57
- data/spec/grape/validations/validators/values_spec.rb +0 -733
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2030
- data/spec/integration/eager_load/eager_load_spec.rb +0 -15
- data/spec/integration/multi_json/json_spec.rb +0 -7
- data/spec/integration/multi_xml/xml_spec.rb +0 -7
- data/spec/shared/deprecated_class_examples.rb +0 -16
- data/spec/shared/versioning_examples.rb +0 -215
- data/spec/spec_helper.rb +0 -52
- data/spec/support/basic_auth_encode_helpers.rb +0 -11
- data/spec/support/chunks.rb +0 -14
- data/spec/support/content_type_helpers.rb +0 -15
- data/spec/support/endpoint_faker.rb +0 -25
- data/spec/support/file_streamer.rb +0 -13
- data/spec/support/integer_helpers.rb +0 -13
- data/spec/support/versioned_helpers.rb +0 -55
@@ -1,122 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Middleware::Versioner::AcceptVersionHeader do
|
4
|
-
subject { described_class.new(app, **(@options || {})) }
|
5
|
-
|
6
|
-
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
|
8
|
-
before do
|
9
|
-
@options = {
|
10
|
-
version_options: {
|
11
|
-
using: :accept_version_header
|
12
|
-
}
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
context 'api.version' do
|
17
|
-
before do
|
18
|
-
@options[:versions] = ['v1']
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'is set' do
|
22
|
-
status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1')
|
23
|
-
expect(env['api.version']).to eql 'v1'
|
24
|
-
expect(status).to eq(200)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'is set if format provided' do
|
28
|
-
status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1')
|
29
|
-
expect(env['api.version']).to eql 'v1'
|
30
|
-
expect(status).to eq(200)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'fails with 406 Not Acceptable if version is not supported' do
|
34
|
-
expect do
|
35
|
-
subject.call('HTTP_ACCEPT_VERSION' => 'v2').last
|
36
|
-
end.to throw_symbol(
|
37
|
-
:error,
|
38
|
-
status: 406,
|
39
|
-
headers: { 'X-Cascade' => 'pass' },
|
40
|
-
message: 'The requested version is not supported.'
|
41
|
-
)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'succeeds if :strict is not set' do
|
46
|
-
expect(subject.call('HTTP_ACCEPT_VERSION' => '').first).to eq(200)
|
47
|
-
expect(subject.call({}).first).to eq(200)
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'succeeds if :strict is set to false' do
|
51
|
-
@options[:version_options][:strict] = false
|
52
|
-
expect(subject.call('HTTP_ACCEPT_VERSION' => '').first).to eq(200)
|
53
|
-
expect(subject.call({}).first).to eq(200)
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'when :strict is set' do
|
57
|
-
before do
|
58
|
-
@options[:versions] = ['v1']
|
59
|
-
@options[:version_options][:strict] = true
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'fails with 406 Not Acceptable if header is not set' do
|
63
|
-
expect do
|
64
|
-
subject.call({}).last
|
65
|
-
end.to throw_symbol(
|
66
|
-
:error,
|
67
|
-
status: 406,
|
68
|
-
headers: { 'X-Cascade' => 'pass' },
|
69
|
-
message: 'Accept-Version header must be set.'
|
70
|
-
)
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'fails with 406 Not Acceptable if header is empty' do
|
74
|
-
expect do
|
75
|
-
subject.call('HTTP_ACCEPT_VERSION' => '').last
|
76
|
-
end.to throw_symbol(
|
77
|
-
:error,
|
78
|
-
status: 406,
|
79
|
-
headers: { 'X-Cascade' => 'pass' },
|
80
|
-
message: 'Accept-Version header must be set.'
|
81
|
-
)
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'succeeds if proper header is set' do
|
85
|
-
expect(subject.call('HTTP_ACCEPT_VERSION' => 'v1').first).to eq(200)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'when :strict and cascade: false' do
|
90
|
-
before do
|
91
|
-
@options[:versions] = ['v1']
|
92
|
-
@options[:version_options][:strict] = true
|
93
|
-
@options[:version_options][:cascade] = false
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'fails with 406 Not Acceptable if header is not set' do
|
97
|
-
expect do
|
98
|
-
subject.call({}).last
|
99
|
-
end.to throw_symbol(
|
100
|
-
:error,
|
101
|
-
status: 406,
|
102
|
-
headers: {},
|
103
|
-
message: 'Accept-Version header must be set.'
|
104
|
-
)
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'fails with 406 Not Acceptable if header is empty' do
|
108
|
-
expect do
|
109
|
-
subject.call('HTTP_ACCEPT_VERSION' => '').last
|
110
|
-
end.to throw_symbol(
|
111
|
-
:error,
|
112
|
-
status: 406,
|
113
|
-
headers: {},
|
114
|
-
message: 'Accept-Version header must be set.'
|
115
|
-
)
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'succeeds if proper header is set' do
|
119
|
-
expect(subject.call('HTTP_ACCEPT_VERSION' => 'v1').first).to eq(200)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
@@ -1,345 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Middleware::Versioner::Header do
|
4
|
-
subject { described_class.new(app, **(@options || {})) }
|
5
|
-
|
6
|
-
let(:app) { ->(env) { [200, env, env] } }
|
7
|
-
|
8
|
-
before do
|
9
|
-
@options = {
|
10
|
-
version_options: {
|
11
|
-
using: :header,
|
12
|
-
vendor: 'vendor'
|
13
|
-
}
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
context 'api.type and api.subtype' do
|
18
|
-
it 'sets type and subtype to first choice of content type if no preference given' do
|
19
|
-
status, _, env = subject.call('HTTP_ACCEPT' => '*/*')
|
20
|
-
expect(env['api.type']).to eql 'application'
|
21
|
-
expect(env['api.subtype']).to eql 'vnd.vendor+xml'
|
22
|
-
expect(status).to eq(200)
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'sets preferred type' do
|
26
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/*')
|
27
|
-
expect(env['api.type']).to eql 'application'
|
28
|
-
expect(env['api.subtype']).to eql 'vnd.vendor+xml'
|
29
|
-
expect(status).to eq(200)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'sets preferred type and subtype' do
|
33
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'text/plain')
|
34
|
-
expect(env['api.type']).to eql 'text'
|
35
|
-
expect(env['api.subtype']).to eql 'plain'
|
36
|
-
expect(status).to eq(200)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'api.format' do
|
41
|
-
it 'is set' do
|
42
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
|
43
|
-
expect(env['api.format']).to eql 'json'
|
44
|
-
expect(status).to eq(200)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'is nil if not provided' do
|
48
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
49
|
-
expect(env['api.format']).to be_nil
|
50
|
-
expect(status).to eq(200)
|
51
|
-
end
|
52
|
-
|
53
|
-
['v1', :v1].each do |version|
|
54
|
-
context "when version is set to #{version}" do
|
55
|
-
before do
|
56
|
-
@options[:versions] = [version]
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'is set' do
|
60
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
61
|
-
expect(env['api.format']).to eql 'json'
|
62
|
-
expect(status).to eq(200)
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'is nil if not provided' do
|
66
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
67
|
-
expect(env['api.format']).to be_nil
|
68
|
-
expect(status).to eq(200)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context 'api.vendor' do
|
75
|
-
it 'is set' do
|
76
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
77
|
-
expect(env['api.vendor']).to eql 'vendor'
|
78
|
-
expect(status).to eq(200)
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'is set if format provided' do
|
82
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
|
83
|
-
expect(env['api.vendor']).to eql 'vendor'
|
84
|
-
expect(status).to eq(200)
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
88
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor+json').last }
|
89
|
-
.to raise_exception do |exception|
|
90
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
91
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
92
|
-
expect(exception.status).to be 406
|
93
|
-
expect(exception.message).to include 'API vendor not found'
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
context 'when version is set' do
|
98
|
-
before do
|
99
|
-
@options[:versions] = ['v1']
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'is set' do
|
103
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
104
|
-
expect(env['api.vendor']).to eql 'vendor'
|
105
|
-
expect(status).to eq(200)
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'is set if format provided' do
|
109
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
110
|
-
expect(env['api.vendor']).to eql 'vendor'
|
111
|
-
expect(status).to eq(200)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
115
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor-v1+json').last }
|
116
|
-
.to raise_exception do |exception|
|
117
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
118
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
119
|
-
expect(exception.status).to be 406
|
120
|
-
expect(exception.message).to include('API vendor not found')
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'api.version' do
|
127
|
-
before do
|
128
|
-
@options[:versions] = ['v1']
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'is set' do
|
132
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
133
|
-
expect(env['api.version']).to eql 'v1'
|
134
|
-
expect(status).to eq(200)
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'is set if format provided' do
|
138
|
-
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
139
|
-
expect(env['api.version']).to eql 'v1'
|
140
|
-
expect(status).to eq(200)
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'fails with 406 Not Acceptable if version is invalid' do
|
144
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
|
145
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
146
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
147
|
-
expect(exception.status).to be 406
|
148
|
-
expect(exception.message).to include('API version not found')
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'succeeds if :strict is not set' do
|
154
|
-
expect(subject.call('HTTP_ACCEPT' => '').first).to eq(200)
|
155
|
-
expect(subject.call({}).first).to eq(200)
|
156
|
-
end
|
157
|
-
|
158
|
-
it 'succeeds if :strict is set to false' do
|
159
|
-
@options[:version_options][:strict] = false
|
160
|
-
expect(subject.call('HTTP_ACCEPT' => '').first).to eq(200)
|
161
|
-
expect(subject.call({}).first).to eq(200)
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'succeeds if :strict is set to false and given an invalid header' do
|
165
|
-
@options[:version_options][:strict] = false
|
166
|
-
expect(subject.call('HTTP_ACCEPT' => 'yaml').first).to eq(200)
|
167
|
-
expect(subject.call({}).first).to eq(200)
|
168
|
-
end
|
169
|
-
|
170
|
-
context 'when :strict is set' do
|
171
|
-
before do
|
172
|
-
@options[:versions] = ['v1']
|
173
|
-
@options[:version_options][:strict] = true
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'fails with 406 Not Acceptable if header is not set' do
|
177
|
-
expect { subject.call({}).last }.to raise_exception do |exception|
|
178
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
179
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
180
|
-
expect(exception.status).to be 406
|
181
|
-
expect(exception.message).to include('Accept header must be set.')
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'fails with 406 Not Acceptable if header is empty' do
|
186
|
-
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
187
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
188
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
189
|
-
expect(exception.status).to be 406
|
190
|
-
expect(exception.message).to include('Accept header must be set.')
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'succeeds if proper header is set' do
|
195
|
-
expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context 'when :strict and cascade: false' do
|
200
|
-
before do
|
201
|
-
@options[:versions] = ['v1']
|
202
|
-
@options[:version_options][:strict] = true
|
203
|
-
@options[:version_options][:cascade] = false
|
204
|
-
end
|
205
|
-
|
206
|
-
it 'fails with 406 Not Acceptable if header is not set' do
|
207
|
-
expect { subject.call({}).last }.to raise_exception do |exception|
|
208
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
209
|
-
expect(exception.headers).to eql({})
|
210
|
-
expect(exception.status).to be 406
|
211
|
-
expect(exception.message).to include('Accept header must be set.')
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'fails with 406 Not Acceptable if header is application/xml' do
|
216
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/xml').last }
|
217
|
-
.to raise_exception do |exception|
|
218
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
219
|
-
expect(exception.headers).to eql({})
|
220
|
-
expect(exception.status).to be 406
|
221
|
-
expect(exception.message).to include('API vendor or version not found.')
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'fails with 406 Not Acceptable if header is empty' do
|
226
|
-
expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
|
227
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
228
|
-
expect(exception.headers).to eql({})
|
229
|
-
expect(exception.status).to be 406
|
230
|
-
expect(exception.message).to include('Accept header must be set.')
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
it 'fails with 406 Not Acceptable if header contains a single invalid accept' do
|
235
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/json;application/vnd.vendor-v1+json').first }
|
236
|
-
.to raise_exception do |exception|
|
237
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
|
238
|
-
expect(exception.headers).to eql({})
|
239
|
-
expect(exception.status).to be 406
|
240
|
-
expect(exception.message).to include('API vendor or version not found.')
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
it 'succeeds if proper header is set' do
|
245
|
-
expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
context 'when multiple versions are specified' do
|
250
|
-
before do
|
251
|
-
@options[:versions] = %w[v1 v2]
|
252
|
-
end
|
253
|
-
|
254
|
-
it 'succeeds with v1' do
|
255
|
-
expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
|
256
|
-
end
|
257
|
-
|
258
|
-
it 'succeeds with v2' do
|
259
|
-
expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').first).to eq(200)
|
260
|
-
end
|
261
|
-
|
262
|
-
it 'fails with another version' do
|
263
|
-
expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
|
264
|
-
expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
|
265
|
-
expect(exception.headers).to eql('X-Cascade' => 'pass')
|
266
|
-
expect(exception.status).to be 406
|
267
|
-
expect(exception.message).to include('API version not found')
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
context 'when there are multiple versions with complex vendor specified with rescue_from :all' do
|
273
|
-
subject do
|
274
|
-
Class.new(Grape::API) do
|
275
|
-
rescue_from :all
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
let(:v1_app) do
|
280
|
-
Class.new(Grape::API) do
|
281
|
-
version 'v1', using: :header, vendor: 'test.a-cool_resource', cascade: false, strict: true
|
282
|
-
content_type :v1_test, 'application/vnd.test.a-cool_resource-v1+json'
|
283
|
-
formatter :v1_test, ->(object, _) { object }
|
284
|
-
format :v1_test
|
285
|
-
|
286
|
-
resources :users do
|
287
|
-
get :hello do
|
288
|
-
'one'
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
let(:v2_app) do
|
295
|
-
Class.new(Grape::API) do
|
296
|
-
version 'v2', using: :header, vendor: 'test.a-cool_resource', strict: true
|
297
|
-
content_type :v2_test, 'application/vnd.test.a-cool_resource-v2+json'
|
298
|
-
formatter :v2_test, ->(object, _) { object }
|
299
|
-
format :v2_test
|
300
|
-
|
301
|
-
resources :users do
|
302
|
-
get :hello do
|
303
|
-
'two'
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def app
|
310
|
-
subject.mount v2_app
|
311
|
-
subject.mount v1_app
|
312
|
-
subject
|
313
|
-
end
|
314
|
-
|
315
|
-
context 'with header versioned endpoints and a rescue_all block defined' do
|
316
|
-
it 'responds correctly to a v1 request' do
|
317
|
-
versioned_get '/users/hello', 'v1', using: :header, vendor: 'test.a-cool_resource'
|
318
|
-
expect(last_response.body).to eq('one')
|
319
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
320
|
-
end
|
321
|
-
|
322
|
-
it 'responds correctly to a v2 request' do
|
323
|
-
versioned_get '/users/hello', 'v2', using: :header, vendor: 'test.a-cool_resource'
|
324
|
-
expect(last_response.body).to eq('two')
|
325
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
context 'with missing vendor option' do
|
331
|
-
subject do
|
332
|
-
Class.new(Grape::API) do
|
333
|
-
version 'v1', using: :header
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
def app
|
338
|
-
subject
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'fails' do
|
342
|
-
expect { versioned_get '/', 'v1', using: :header }.to raise_error Grape::Exceptions::MissingVendorOption
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|
@@ -1,171 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Middleware::Versioner::Param do
|
4
|
-
subject { described_class.new(app, **options) }
|
5
|
-
|
6
|
-
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
|
-
let(:options) { {} }
|
8
|
-
|
9
|
-
it 'sets the API version based on the default param (apiver)' do
|
10
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
11
|
-
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'cuts (only) the version out of the params' do
|
15
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1', 'other_param' => '5' })
|
16
|
-
env['rack.request.query_hash'] = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
17
|
-
expect(subject.call(env)[1]['rack.request.query_hash']['apiver']).to be_nil
|
18
|
-
expect(subject.call(env)[1]['rack.request.query_hash']['other_param']).to eq('5')
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'provides a nil version if no version is given' do
|
22
|
-
env = Rack::MockRequest.env_for('/')
|
23
|
-
expect(subject.call(env).last).to be_nil
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'with specified parameter name' do
|
27
|
-
let(:options) { { version_options: { parameter: 'v' } } }
|
28
|
-
|
29
|
-
it 'sets the API version based on the custom parameter name' do
|
30
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
|
31
|
-
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'does not set the API version based on the default param' do
|
35
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
36
|
-
expect(subject.call(env)[1]['api.version']).to be_nil
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'with specified versions' do
|
41
|
-
let(:options) { { versions: %w[v1 v2] } }
|
42
|
-
|
43
|
-
it 'throws an error if a non-allowed version is specified' do
|
44
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
|
45
|
-
expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'allows versions that have been specified' do
|
49
|
-
env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
|
50
|
-
expect(subject.call(env)[1]['api.version']).to eq('v1')
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context 'when no version is set' do
|
55
|
-
let(:options) do
|
56
|
-
{
|
57
|
-
versions: ['v1'],
|
58
|
-
version_options: { using: :header }
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'returns a 200 (matches the first version found)' do
|
63
|
-
env = Rack::MockRequest.env_for('/awesome', params: {})
|
64
|
-
expect(subject.call(env).first).to eq(200)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context 'when there are multiple versions without a custom param' do
|
69
|
-
subject { Class.new(Grape::API) }
|
70
|
-
|
71
|
-
let(:v1_app) do
|
72
|
-
Class.new(Grape::API) do
|
73
|
-
version 'v1', using: :param
|
74
|
-
content_type :v1_test, 'application/vnd.test.a-cool_resource-v1+json'
|
75
|
-
formatter :v1_test, ->(object, _) { object }
|
76
|
-
format :v1_test
|
77
|
-
|
78
|
-
resources :users do
|
79
|
-
get :hello do
|
80
|
-
'one'
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
let(:v2_app) do
|
87
|
-
Class.new(Grape::API) do
|
88
|
-
version 'v2', using: :param
|
89
|
-
content_type :v2_test, 'application/vnd.test.a-cool_resource-v2+json'
|
90
|
-
formatter :v2_test, ->(object, _) { object }
|
91
|
-
format :v2_test
|
92
|
-
|
93
|
-
resources :users do
|
94
|
-
get :hello do
|
95
|
-
'two'
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def app
|
102
|
-
subject.mount v2_app
|
103
|
-
subject.mount v1_app
|
104
|
-
subject
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'responds correctly to a v1 request' do
|
108
|
-
versioned_get '/users/hello', 'v1', using: :param, parameter: :apiver
|
109
|
-
expect(last_response.body).to eq('one')
|
110
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'responds correctly to a v2 request' do
|
114
|
-
versioned_get '/users/hello', 'v2', using: :param, parameter: :apiver
|
115
|
-
expect(last_response.body).to eq('two')
|
116
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context 'when there are multiple versions with a custom param' do
|
121
|
-
subject { Class.new(Grape::API) }
|
122
|
-
|
123
|
-
let(:v1_app) do
|
124
|
-
Class.new(Grape::API) do
|
125
|
-
version 'v1', using: :param, parameter: 'v'
|
126
|
-
content_type :v1_test, 'application/vnd.test.a-cool_resource-v1+json'
|
127
|
-
formatter :v1_test, ->(object, _) { object }
|
128
|
-
format :v1_test
|
129
|
-
|
130
|
-
resources :users do
|
131
|
-
get :hello do
|
132
|
-
'one'
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
let(:v2_app) do
|
139
|
-
Class.new(Grape::API) do
|
140
|
-
version 'v2', using: :param, parameter: 'v'
|
141
|
-
content_type :v2_test, 'application/vnd.test.a-cool_resource-v2+json'
|
142
|
-
formatter :v2_test, ->(object, _) { object }
|
143
|
-
format :v2_test
|
144
|
-
|
145
|
-
resources :users do
|
146
|
-
get :hello do
|
147
|
-
'two'
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def app
|
154
|
-
subject.mount v2_app
|
155
|
-
subject.mount v1_app
|
156
|
-
subject
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'responds correctly to a v1 request' do
|
160
|
-
versioned_get '/users/hello', 'v1', using: :param, parameter: 'v'
|
161
|
-
expect(last_response.body).to eq('one')
|
162
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'responds correctly to a v2 request' do
|
166
|
-
versioned_get '/users/hello', 'v2', using: :param, parameter: 'v'
|
167
|
-
expect(last_response.body).to eq('two')
|
168
|
-
expect(last_response.body).not_to include('API vendor or version not found')
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Middleware::Versioner::Path do
|
4
|
-
subject { described_class.new(app, **options) }
|
5
|
-
|
6
|
-
let(:app) { ->(env) { [200, env, env['api.version']] } }
|
7
|
-
let(:options) { {} }
|
8
|
-
|
9
|
-
it 'sets the API version based on the first path' do
|
10
|
-
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'does not cut the version out of the path' do
|
14
|
-
expect(subject.call('PATH_INFO' => '/v1/awesome')[1]['PATH_INFO']).to eq('/v1/awesome')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'provides a nil version if no path is given' do
|
18
|
-
expect(subject.call('PATH_INFO' => '/').last).to be_nil
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with a pattern' do
|
22
|
-
let(:options) { { pattern: /v./i } }
|
23
|
-
|
24
|
-
it 'sets the version if it matches' do
|
25
|
-
expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'ignores the version if it fails to match' do
|
29
|
-
expect(subject.call('PATH_INFO' => '/awesome/radical').last).to be_nil
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
[%w[v1 v2], %i[v1 v2], [:v1, 'v2'], ['v1', :v2]].each do |versions|
|
34
|
-
context "with specified versions as #{versions}" do
|
35
|
-
let(:options) { { versions: versions } }
|
36
|
-
|
37
|
-
it 'throws an error if a non-allowed version is specified' do
|
38
|
-
expect(catch(:error) { subject.call('PATH_INFO' => '/v3/awesome') }[:status]).to eq(404)
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'allows versions that have been specified' do
|
42
|
-
expect(subject.call('PATH_INFO' => '/v1/asoasd').last).to eq('v1')
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'with prefix, but requested version is not matched' do
|
48
|
-
let(:options) { { prefix: '/v1', pattern: /v./i } }
|
49
|
-
|
50
|
-
it 'recognizes potential version' do
|
51
|
-
expect(subject.call('PATH_INFO' => '/v3/foo').last).to eq('v3')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'with mount path' do
|
56
|
-
let(:options) { { mount_path: '/mounted', versions: [:v1] } }
|
57
|
-
|
58
|
-
it 'recognizes potential version' do
|
59
|
-
expect(subject.call('PATH_INFO' => '/mounted/v1/foo').last).to eq('v1')
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|