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