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.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +19 -22
  4. data/UPGRADING.md +35 -0
  5. data/grape.gemspec +1 -4
  6. data/lib/grape/dsl/desc.rb +1 -1
  7. data/lib/grape/dsl/inside_route.rb +9 -9
  8. data/lib/grape/endpoint.rb +9 -1
  9. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  10. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  11. data/lib/grape/http/headers.rb +12 -2
  12. data/lib/grape/middleware/auth/strategies.rb +1 -2
  13. data/lib/grape/middleware/error.rb +4 -4
  14. data/lib/grape/middleware/formatter.rb +5 -5
  15. data/lib/grape/railtie.rb +9 -0
  16. data/lib/grape/request.rb +8 -2
  17. data/lib/grape/router/route.rb +1 -1
  18. data/lib/grape/validations/validators/base.rb +1 -1
  19. data/lib/grape/validations/validators/values_validator.rb +2 -2
  20. data/lib/grape/version.rb +1 -1
  21. data/lib/grape.rb +15 -2
  22. metadata +8 -243
  23. data/spec/grape/api/custom_validations_spec.rb +0 -213
  24. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  25. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  26. data/spec/grape/api/documentation_spec.rb +0 -59
  27. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  28. data/spec/grape/api/instance_spec.rb +0 -103
  29. data/spec/grape/api/invalid_format_spec.rb +0 -45
  30. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  31. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  32. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  33. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  34. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  35. data/spec/grape/api/recognize_path_spec.rb +0 -21
  36. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  37. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  38. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  39. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  40. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  41. data/spec/grape/api_remount_spec.rb +0 -509
  42. data/spec/grape/api_spec.rb +0 -4356
  43. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  44. data/spec/grape/dsl/desc_spec.rb +0 -98
  45. data/spec/grape/dsl/headers_spec.rb +0 -62
  46. data/spec/grape/dsl/helpers_spec.rb +0 -100
  47. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  48. data/spec/grape/dsl/logger_spec.rb +0 -24
  49. data/spec/grape/dsl/middleware_spec.rb +0 -60
  50. data/spec/grape/dsl/parameters_spec.rb +0 -180
  51. data/spec/grape/dsl/request_response_spec.rb +0 -225
  52. data/spec/grape/dsl/routing_spec.rb +0 -275
  53. data/spec/grape/dsl/settings_spec.rb +0 -261
  54. data/spec/grape/dsl/validations_spec.rb +0 -55
  55. data/spec/grape/endpoint/declared_spec.rb +0 -846
  56. data/spec/grape/endpoint_spec.rb +0 -1085
  57. data/spec/grape/entity_spec.rb +0 -336
  58. data/spec/grape/exceptions/base_spec.rb +0 -81
  59. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  60. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  61. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  62. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  63. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  64. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  65. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  66. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  67. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  68. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  69. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  70. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  71. data/spec/grape/exceptions/validation_spec.rb +0 -19
  72. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  73. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  74. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  75. data/spec/grape/grape_spec.rb +0 -9
  76. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  77. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  78. data/spec/grape/integration/rack_spec.rb +0 -51
  79. data/spec/grape/loading_spec.rb +0 -44
  80. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  81. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  82. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  83. data/spec/grape/middleware/base_spec.rb +0 -221
  84. data/spec/grape/middleware/error_spec.rb +0 -85
  85. data/spec/grape/middleware/exception_spec.rb +0 -294
  86. data/spec/grape/middleware/formatter_spec.rb +0 -461
  87. data/spec/grape/middleware/globals_spec.rb +0 -30
  88. data/spec/grape/middleware/stack_spec.rb +0 -155
  89. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  90. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  91. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  92. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  93. data/spec/grape/middleware/versioner_spec.rb +0 -21
  94. data/spec/grape/named_api_spec.rb +0 -19
  95. data/spec/grape/parser_spec.rb +0 -86
  96. data/spec/grape/path_spec.rb +0 -252
  97. data/spec/grape/presenters/presenter_spec.rb +0 -71
  98. data/spec/grape/request_spec.rb +0 -126
  99. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  100. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  101. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  102. data/spec/grape/util/stackable_values_spec.rb +0 -128
  103. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  104. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  105. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  106. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  107. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  108. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  109. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  110. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  111. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  112. data/spec/grape/validations/types_spec.rb +0 -111
  113. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  114. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  115. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  116. data/spec/grape/validations/validators/base_spec.rb +0 -38
  117. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  118. data/spec/grape/validations/validators/default_spec.rb +0 -463
  119. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  120. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  121. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  122. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  123. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  124. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  125. data/spec/grape/validations/validators/values_spec.rb +0 -733
  126. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  127. data/spec/grape/validations_spec.rb +0 -2030
  128. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  129. data/spec/integration/multi_json/json_spec.rb +0 -7
  130. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  131. data/spec/shared/deprecated_class_examples.rb +0 -16
  132. data/spec/shared/versioning_examples.rb +0 -215
  133. data/spec/spec_helper.rb +0 -52
  134. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  135. data/spec/support/chunks.rb +0 -14
  136. data/spec/support/content_type_helpers.rb +0 -15
  137. data/spec/support/endpoint_faker.rb +0 -25
  138. data/spec/support/file_streamer.rb +0 -13
  139. data/spec/support/integer_helpers.rb +0 -13
  140. 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