grape 1.8.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -1
  3. data/README.md +377 -334
  4. data/UPGRADING.md +231 -6
  5. data/grape.gemspec +6 -10
  6. data/lib/grape/api/instance.rb +13 -10
  7. data/lib/grape/api.rb +17 -8
  8. data/lib/grape/content_types.rb +0 -2
  9. data/lib/grape/cookies.rb +2 -1
  10. data/lib/grape/dry_types.rb +0 -2
  11. data/lib/grape/dsl/desc.rb +23 -21
  12. data/lib/grape/dsl/headers.rb +1 -1
  13. data/lib/grape/dsl/inside_route.rb +47 -22
  14. data/lib/grape/dsl/parameters.rb +4 -3
  15. data/lib/grape/dsl/routing.rb +20 -4
  16. data/lib/grape/dsl/validations.rb +13 -0
  17. data/lib/grape/endpoint.rb +15 -10
  18. data/lib/grape/{util/env.rb → env.rb} +0 -5
  19. data/lib/grape/error_formatter/txt.rb +11 -10
  20. data/lib/grape/exceptions/base.rb +3 -3
  21. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  22. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  23. data/lib/grape/exceptions/validation.rb +0 -2
  24. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  25. data/lib/grape/exceptions/validation_errors.rb +1 -3
  26. data/lib/grape/extensions/hash.rb +5 -1
  27. data/lib/grape/http/headers.rb +18 -24
  28. data/lib/grape/{util/json.rb → json.rb} +1 -3
  29. data/lib/grape/locale/en.yml +3 -0
  30. data/lib/grape/middleware/auth/base.rb +0 -2
  31. data/lib/grape/middleware/auth/dsl.rb +0 -2
  32. data/lib/grape/middleware/auth/strategies.rb +1 -2
  33. data/lib/grape/middleware/base.rb +0 -2
  34. data/lib/grape/middleware/error.rb +55 -50
  35. data/lib/grape/middleware/formatter.rb +21 -18
  36. data/lib/grape/middleware/globals.rb +1 -3
  37. data/lib/grape/middleware/stack.rb +2 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
  39. data/lib/grape/middleware/versioner/header.rb +17 -163
  40. data/lib/grape/middleware/versioner/param.rb +2 -4
  41. data/lib/grape/middleware/versioner/path.rb +1 -3
  42. data/lib/grape/namespace.rb +3 -4
  43. data/lib/grape/path.rb +24 -29
  44. data/lib/grape/railtie.rb +9 -0
  45. data/lib/grape/request.rb +3 -5
  46. data/lib/grape/router/base_route.rb +39 -0
  47. data/lib/grape/router/greedy_route.rb +20 -0
  48. data/lib/grape/router/pattern.rb +39 -30
  49. data/lib/grape/router/route.rb +22 -59
  50. data/lib/grape/router.rb +30 -36
  51. data/lib/grape/util/accept/header.rb +19 -0
  52. data/lib/grape/util/accept_header_handler.rb +105 -0
  53. data/lib/grape/util/base_inheritable.rb +4 -4
  54. data/lib/grape/util/cache.rb +0 -3
  55. data/lib/grape/util/endpoint_configuration.rb +1 -1
  56. data/lib/grape/util/header.rb +13 -0
  57. data/lib/grape/util/inheritable_values.rb +0 -2
  58. data/lib/grape/util/lazy/block.rb +29 -0
  59. data/lib/grape/util/lazy/object.rb +45 -0
  60. data/lib/grape/util/lazy/value.rb +38 -0
  61. data/lib/grape/util/lazy/value_array.rb +21 -0
  62. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  63. data/lib/grape/util/lazy/value_hash.rb +21 -0
  64. data/lib/grape/util/media_type.rb +70 -0
  65. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  66. data/lib/grape/util/stackable_values.rb +1 -6
  67. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  68. data/lib/grape/validations/attributes_doc.rb +38 -36
  69. data/lib/grape/validations/contract_scope.rb +71 -0
  70. data/lib/grape/validations/params_scope.rb +10 -9
  71. data/lib/grape/validations/types/array_coercer.rb +0 -2
  72. data/lib/grape/validations/types/build_coercer.rb +69 -71
  73. data/lib/grape/validations/types/dry_type_coercer.rb +1 -11
  74. data/lib/grape/validations/types/json.rb +0 -2
  75. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  76. data/lib/grape/validations/types/set_coercer.rb +0 -3
  77. data/lib/grape/validations/types.rb +0 -3
  78. data/lib/grape/validations/validators/base.rb +2 -1
  79. data/lib/grape/validations/validators/default_validator.rb +5 -1
  80. data/lib/grape/validations/validators/length_validator.rb +42 -0
  81. data/lib/grape/validations/validators/values_validator.rb +8 -3
  82. data/lib/grape/validations.rb +3 -7
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  85. data/lib/grape.rb +38 -269
  86. metadata +33 -274
  87. data/lib/grape/eager_load.rb +0 -20
  88. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  89. data/lib/grape/router/attribute_translator.rb +0 -63
  90. data/lib/grape/util/lazy_block.rb +0 -27
  91. data/lib/grape/util/lazy_object.rb +0 -43
  92. data/lib/grape/util/lazy_value.rb +0 -91
  93. data/spec/grape/api/custom_validations_spec.rb +0 -213
  94. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  95. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  96. data/spec/grape/api/documentation_spec.rb +0 -59
  97. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  98. data/spec/grape/api/instance_spec.rb +0 -103
  99. data/spec/grape/api/invalid_format_spec.rb +0 -45
  100. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  101. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  102. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  103. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  104. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  105. data/spec/grape/api/recognize_path_spec.rb +0 -21
  106. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  107. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  108. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  109. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  110. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  111. data/spec/grape/api_remount_spec.rb +0 -509
  112. data/spec/grape/api_spec.rb +0 -4356
  113. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  114. data/spec/grape/dsl/desc_spec.rb +0 -98
  115. data/spec/grape/dsl/headers_spec.rb +0 -62
  116. data/spec/grape/dsl/helpers_spec.rb +0 -100
  117. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  118. data/spec/grape/dsl/logger_spec.rb +0 -24
  119. data/spec/grape/dsl/middleware_spec.rb +0 -60
  120. data/spec/grape/dsl/parameters_spec.rb +0 -180
  121. data/spec/grape/dsl/request_response_spec.rb +0 -225
  122. data/spec/grape/dsl/routing_spec.rb +0 -275
  123. data/spec/grape/dsl/settings_spec.rb +0 -261
  124. data/spec/grape/dsl/validations_spec.rb +0 -55
  125. data/spec/grape/endpoint/declared_spec.rb +0 -846
  126. data/spec/grape/endpoint_spec.rb +0 -1085
  127. data/spec/grape/entity_spec.rb +0 -336
  128. data/spec/grape/exceptions/base_spec.rb +0 -81
  129. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  130. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  131. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  132. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  133. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  134. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  135. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  136. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  137. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  138. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  139. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  140. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  141. data/spec/grape/exceptions/validation_spec.rb +0 -19
  142. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  143. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  144. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  145. data/spec/grape/grape_spec.rb +0 -9
  146. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  147. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  148. data/spec/grape/integration/rack_spec.rb +0 -51
  149. data/spec/grape/loading_spec.rb +0 -44
  150. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  151. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  152. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  153. data/spec/grape/middleware/base_spec.rb +0 -221
  154. data/spec/grape/middleware/error_spec.rb +0 -85
  155. data/spec/grape/middleware/exception_spec.rb +0 -294
  156. data/spec/grape/middleware/formatter_spec.rb +0 -461
  157. data/spec/grape/middleware/globals_spec.rb +0 -30
  158. data/spec/grape/middleware/stack_spec.rb +0 -155
  159. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  160. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  161. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  162. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  163. data/spec/grape/middleware/versioner_spec.rb +0 -21
  164. data/spec/grape/named_api_spec.rb +0 -19
  165. data/spec/grape/parser_spec.rb +0 -86
  166. data/spec/grape/path_spec.rb +0 -252
  167. data/spec/grape/presenters/presenter_spec.rb +0 -71
  168. data/spec/grape/request_spec.rb +0 -126
  169. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  170. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  171. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  172. data/spec/grape/util/stackable_values_spec.rb +0 -128
  173. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  174. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  175. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  176. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  177. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  178. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  179. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  180. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  181. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  182. data/spec/grape/validations/types_spec.rb +0 -111
  183. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  184. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  185. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  186. data/spec/grape/validations/validators/base_spec.rb +0 -38
  187. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  188. data/spec/grape/validations/validators/default_spec.rb +0 -463
  189. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  190. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  191. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  192. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  193. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  194. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  195. data/spec/grape/validations/validators/values_spec.rb +0 -733
  196. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  197. data/spec/grape/validations_spec.rb +0 -2030
  198. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  199. data/spec/integration/multi_json/json_spec.rb +0 -7
  200. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  201. data/spec/shared/deprecated_class_examples.rb +0 -16
  202. data/spec/shared/versioning_examples.rb +0 -215
  203. data/spec/spec_helper.rb +0 -52
  204. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  205. data/spec/support/chunks.rb +0 -14
  206. data/spec/support/content_type_helpers.rb +0 -15
  207. data/spec/support/endpoint_faker.rb +0 -25
  208. data/spec/support/file_streamer.rb +0 -13
  209. data/spec/support/integer_helpers.rb +0 -13
  210. data/spec/support/versioned_helpers.rb +0 -55
@@ -1,733 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::ValuesValidator do
4
- let_it_be(:values_model) do
5
- Class.new do
6
- DEFAULT_VALUES = %w[valid-type1 valid-type2 valid-type3].freeze
7
- DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze
8
-
9
- class << self
10
- def values
11
- @values ||= []
12
- [DEFAULT_VALUES + @values].flatten.uniq
13
- end
14
-
15
- def add_value(value)
16
- @values ||= []
17
- @values << value
18
- end
19
-
20
- def excepts
21
- @excepts ||= []
22
- [DEFAULT_EXCEPTS + @excepts].flatten.uniq
23
- end
24
-
25
- def add_except(except)
26
- @excepts ||= []
27
- @excepts << except
28
- end
29
-
30
- def include?(value)
31
- values.include?(value)
32
- end
33
-
34
- def even?(value)
35
- value.to_i.even?
36
- end
37
- end
38
- end
39
- end
40
-
41
- before do
42
- stub_const('ValuesModel', values_model)
43
- end
44
-
45
- let_it_be(:app) do
46
- ValuesModel = values_model
47
- Class.new(Grape::API) do
48
- default_format :json
49
-
50
- resources :custom_message do
51
- params do
52
- requires :type, values: { value: ValuesModel.values, message: 'value does not include in values' }
53
- end
54
- get '/' do
55
- { type: params[:type] }
56
- end
57
-
58
- params do
59
- optional :type, values: { value: -> { ValuesModel.values }, message: 'value does not include in values' }, default: 'valid-type2'
60
- end
61
- get '/lambda' do
62
- { type: params[:type] }
63
- end
64
-
65
- params do
66
- requires :type, values: { except: ValuesModel.excepts, except_message: 'value is on exclusions list', message: 'default exclude message' }
67
- end
68
- get '/exclude/exclude_message'
69
-
70
- params do
71
- requires :type, values: { except: -> { ValuesModel.excepts }, except_message: 'value is on exclusions list' }
72
- end
73
- get '/exclude/lambda/exclude_message'
74
-
75
- params do
76
- requires :type, values: { except: ValuesModel.excepts, message: 'default exclude message' }
77
- end
78
- get '/exclude/fallback_message'
79
- end
80
-
81
- params do
82
- requires :type, values: ValuesModel.values
83
- end
84
- get '/' do
85
- { type: params[:type] }
86
- end
87
-
88
- params do
89
- requires :type, values: []
90
- end
91
- get '/empty'
92
-
93
- params do
94
- optional :type, values: { value: ValuesModel.values }, default: 'valid-type2'
95
- end
96
- get '/default/hash/valid' do
97
- { type: params[:type] }
98
- end
99
-
100
- params do
101
- optional :type, values: ValuesModel.values, default: 'valid-type2'
102
- end
103
- get '/default/valid' do
104
- { type: params[:type] }
105
- end
106
-
107
- params do
108
- optional :type, values: { except: ValuesModel.excepts }, default: 'valid-type2'
109
- end
110
- get '/default/except' do
111
- { type: params[:type] }
112
- end
113
-
114
- params do
115
- optional :type, values: -> { ValuesModel.values }, default: 'valid-type2'
116
- end
117
- get '/lambda' do
118
- { type: params[:type] }
119
- end
120
-
121
- params do
122
- optional :type, type: Integer, values: 1..
123
- end
124
- get '/endless' do
125
- { type: params[:type] }
126
- end
127
-
128
- params do
129
- requires :type, values: ->(v) { ValuesModel.include? v }
130
- end
131
- get '/lambda_val' do
132
- { type: params[:type] }
133
- end
134
-
135
- params do
136
- requires :number, type: Integer, values: ->(v) { v > 0 }
137
- end
138
- get '/lambda_int_val' do
139
- { number: params[:number] }
140
- end
141
-
142
- params do
143
- requires :type, values: -> { [] }
144
- end
145
- get '/empty_lambda'
146
-
147
- params do
148
- optional :type, values: ValuesModel.values, default: -> { ValuesModel.values.sample }
149
- end
150
- get '/default_lambda' do
151
- { type: params[:type] }
152
- end
153
-
154
- params do
155
- optional :type, values: -> { ValuesModel.values }, default: -> { ValuesModel.values.sample }
156
- end
157
- get '/default_and_values_lambda' do
158
- { type: params[:type] }
159
- end
160
-
161
- params do
162
- optional :type, type: Grape::API::Boolean, desc: 'A boolean', values: [true]
163
- end
164
- get '/values/optional_boolean' do
165
- { type: params[:type] }
166
- end
167
-
168
- params do
169
- requires :type, type: Integer, desc: 'An integer', values: [10, 11], default: 10
170
- end
171
- get '/values/coercion' do
172
- { type: params[:type] }
173
- end
174
-
175
- params do
176
- requires :type, type: Array[Integer], desc: 'An integer', values: [10, 11], default: 10
177
- end
178
- get '/values/array_coercion' do
179
- { type: params[:type] }
180
- end
181
-
182
- params do
183
- optional :optional, type: Array do
184
- requires :type, values: %w[a b]
185
- end
186
- end
187
- get '/optional_with_required_values'
188
-
189
- params do
190
- requires :type, values: { except: ValuesModel.excepts }
191
- end
192
- get '/except/exclusive' do
193
- { type: params[:type] }
194
- end
195
-
196
- params do
197
- requires :type, type: String, values: { except: ValuesModel.excepts }
198
- end
199
- get '/except/exclusive/type' do
200
- { type: params[:type] }
201
- end
202
-
203
- params do
204
- requires :type, values: { except: -> { ValuesModel.excepts } }
205
- end
206
- get '/except/exclusive/lambda' do
207
- { type: params[:type] }
208
- end
209
-
210
- params do
211
- requires :type, type: String, values: { except: -> { ValuesModel.excepts } }
212
- end
213
- get '/except/exclusive/lambda/type' do
214
- { type: params[:type] }
215
- end
216
-
217
- params do
218
- requires :type, type: Integer, values: { except: -> { [3, 4, 5] } }
219
- end
220
- get '/except/exclusive/lambda/coercion' do
221
- { type: params[:type] }
222
- end
223
-
224
- params do
225
- requires :type, type: Integer, values: { value: 1..5, except: [3] }
226
- end
227
- get '/mixed/value/except' do
228
- { type: params[:type] }
229
- end
230
-
231
- params do
232
- optional :optional, type: Array[String], values: %w[a b c]
233
- end
234
- put '/optional_with_array_of_string_values'
235
-
236
- params do
237
- requires :type, values: { proc: ->(v) { ValuesModel.include? v } }
238
- end
239
- get '/proc' do
240
- { type: params[:type] }
241
- end
242
-
243
- params do
244
- requires :type, values: { proc: ->(v) { ValuesModel.include? v }, message: 'failed check' }
245
- end
246
- get '/proc/message'
247
-
248
- params do
249
- requires :number, values: { value: ->(v) { ValuesModel.even? v }, message: 'must be even' }
250
- end
251
- get '/proc/custom_message' do
252
- { message: 'success' }
253
- end
254
-
255
- params do
256
- requires :input_one, :input_two, values: { value: ->(v1, v2) { v1 + v2 > 10 } }
257
- end
258
- get '/proc/arity2'
259
-
260
- params do
261
- optional :name, type: String, values: %w[a b], allow_blank: true
262
- end
263
- get '/allow_blank'
264
- end
265
- end
266
-
267
- context 'with a custom validation message' do
268
- it 'allows a valid value for a parameter' do
269
- get('/custom_message', type: 'valid-type1')
270
- expect(last_response.status).to eq 200
271
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
272
- end
273
-
274
- it 'does not allow an invalid value for a parameter' do
275
- get('/custom_message', type: 'invalid-type')
276
- expect(last_response.status).to eq 400
277
- expect(last_response.body).to eq({ error: 'type value does not include in values' }.to_json)
278
- end
279
-
280
- it 'validates against values in a proc' do
281
- ValuesModel.add_value('valid-type4')
282
-
283
- get('/custom_message/lambda', type: 'valid-type4')
284
- expect(last_response.status).to eq 200
285
- expect(last_response.body).to eq({ type: 'valid-type4' }.to_json)
286
- end
287
-
288
- it 'does not allow an invalid value for a parameter using lambda' do
289
- get('/custom_message/lambda', type: 'invalid-type')
290
- expect(last_response.status).to eq 400
291
- expect(last_response.body).to eq({ error: 'type value does not include in values' }.to_json)
292
- end
293
- end
294
-
295
- context 'with a custom exclude validation message' do
296
- it 'does not allow an invalid value for a parameter' do
297
- get('/custom_message/exclude/exclude_message', type: 'invalid-type1')
298
- expect(last_response.status).to eq 400
299
- expect(last_response.body).to eq({ error: 'type value is on exclusions list' }.to_json)
300
- end
301
- end
302
-
303
- context 'with a custom exclude validation message' do
304
- it 'does not allow an invalid value for a parameter' do
305
- get('/custom_message/exclude/lambda/exclude_message', type: 'invalid-type1')
306
- expect(last_response.status).to eq 400
307
- expect(last_response.body).to eq({ error: 'type value is on exclusions list' }.to_json)
308
- end
309
- end
310
-
311
- context 'exclude with a standard custom validation message' do
312
- it 'does not allow an invalid value for a parameter' do
313
- get('/custom_message/exclude/fallback_message', type: 'invalid-type1')
314
- expect(last_response.status).to eq 400
315
- expect(last_response.body).to eq({ error: 'type default exclude message' }.to_json)
316
- end
317
- end
318
-
319
- it 'allows a valid value for a parameter' do
320
- get('/', type: 'valid-type1')
321
- expect(last_response.status).to eq 200
322
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
323
- end
324
-
325
- it 'does not allow an invalid value for a parameter' do
326
- get('/', type: 'invalid-type')
327
- expect(last_response.status).to eq 400
328
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
329
- end
330
-
331
- it 'rejects all values if values is an empty array' do
332
- get('/empty', type: 'invalid-type')
333
- expect(last_response.status).to eq 400
334
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
335
- end
336
-
337
- context 'nil value for a parameter' do
338
- it 'does not allow for root params scope' do
339
- get('/', type: nil)
340
- expect(last_response.status).to eq 400
341
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
342
- end
343
-
344
- it 'allows for a required param in child scope' do
345
- get('/optional_with_required_values')
346
- expect(last_response.status).to eq 200
347
- end
348
-
349
- it 'accepts for an optional param with a list of values' do
350
- put('/optional_with_array_of_string_values', optional: nil)
351
- expect(last_response.status).to eq 200
352
- end
353
- end
354
-
355
- it 'allows a valid default value' do
356
- get('/default/valid')
357
- expect(last_response.status).to eq 200
358
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
359
- end
360
-
361
- it 'allows a default value with except' do
362
- get('/default/except')
363
- expect(last_response.status).to eq 200
364
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
365
- end
366
-
367
- it 'allows a valid default value' do
368
- get('/default/hash/valid')
369
- expect(last_response.status).to eq 200
370
- expect(last_response.body).to eq({ type: 'valid-type2' }.to_json)
371
- end
372
-
373
- it 'allows a proc for values' do
374
- get('/lambda', type: 'valid-type1')
375
- expect(last_response.status).to eq 200
376
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
377
- end
378
-
379
- it 'does not validate updated values without proc' do
380
- ValuesModel.add_value('valid-type4')
381
- get('/', type: 'valid-type4')
382
- expect(last_response.status).to eq 400
383
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
384
- end
385
-
386
- it 'validates against values in a proc' do
387
- ValuesModel.add_value('valid-type4')
388
-
389
- get('/lambda', type: 'valid-type4')
390
- expect(last_response.status).to eq 200
391
- expect(last_response.body).to eq({ type: 'valid-type4' }.to_json)
392
- end
393
-
394
- it 'does not allow an invalid value for a parameter using lambda' do
395
- get('/lambda', type: 'invalid-type')
396
- expect(last_response.status).to eq 400
397
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
398
- end
399
-
400
- it 'validates against values in an endless range', if: ActiveSupport::VERSION::MAJOR >= 6 do
401
- get('/endless', type: 10)
402
- expect(last_response.status).to eq 200
403
- expect(last_response.body).to eq({ type: 10 }.to_json)
404
- end
405
-
406
- it 'does not allow an invalid value for a parameter using an endless range', if: ActiveSupport::VERSION::MAJOR >= 6 do
407
- get('/endless', type: 0)
408
- expect(last_response.status).to eq 400
409
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
410
- end
411
-
412
- it 'does not allow non-numeric string value for int value using lambda' do
413
- get('/lambda_int_val', number: 'foo')
414
- expect(last_response.status).to eq 400
415
- expect(last_response.body).to eq({ error: 'number is invalid, number does not have a valid value' }.to_json)
416
- end
417
-
418
- it 'does not allow nil for int value using lambda' do
419
- get('/lambda_int_val', number: nil)
420
- expect(last_response.status).to eq 400
421
- expect(last_response.body).to eq({ error: 'number does not have a valid value' }.to_json)
422
- end
423
-
424
- it 'allows numeric string for int value using lambda' do
425
- get('/lambda_int_val', number: '3')
426
- expect(last_response.status).to eq 200
427
- expect(last_response.body).to eq({ number: 3 }.to_json)
428
- end
429
-
430
- it 'allows value using lambda' do
431
- get('/lambda_val', type: 'valid-type1')
432
- expect(last_response.status).to eq 200
433
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
434
- end
435
-
436
- it 'does not allow invalid value using lambda' do
437
- get('/lambda_val', type: 'invalid-type')
438
- expect(last_response.status).to eq 400
439
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
440
- end
441
-
442
- it 'validates against an empty array in a proc' do
443
- get('/empty_lambda', type: 'any')
444
- expect(last_response.status).to eq 400
445
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
446
- end
447
-
448
- it 'validates default value from proc' do
449
- get('/default_lambda')
450
- expect(last_response.status).to eq 200
451
- end
452
-
453
- it 'validates default value from proc against values in a proc' do
454
- get('/default_and_values_lambda')
455
- expect(last_response.status).to eq 200
456
- end
457
-
458
- it 'raises IncompatibleOptionValues on an invalid default value from proc' do
459
- subject = Class.new(Grape::API)
460
- expect do
461
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], default: "#{ValuesModel.values.sample}_invalid" }
462
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
463
- end
464
-
465
- it 'raises IncompatibleOptionValues on an invalid default value' do
466
- subject = Class.new(Grape::API)
467
- expect do
468
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], default: 'invalid-type' }
469
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
470
- end
471
-
472
- it 'raises IncompatibleOptionValues when type is incompatible with values array' do
473
- subject = Class.new(Grape::API)
474
- expect do
475
- subject.params { optional :type, values: %w[valid-type1 valid-type2 valid-type3], type: Symbol }
476
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
477
- end
478
-
479
- context 'boolean values' do
480
- it 'allows a value from the list' do
481
- get('/values/optional_boolean', type: true)
482
-
483
- expect(last_response.status).to eq 200
484
- expect(last_response.body).to eq({ type: true }.to_json)
485
- end
486
-
487
- it 'rejects a value which is not in the list' do
488
- get('/values/optional_boolean', type: false)
489
-
490
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
491
- end
492
- end
493
-
494
- it 'allows values to be a kind of the coerced type not just an instance of it' do
495
- get('/values/coercion', type: 10)
496
- expect(last_response.status).to eq 200
497
- expect(last_response.body).to eq({ type: 10 }.to_json)
498
- end
499
-
500
- it 'allows values to be a kind of the coerced type in an array' do
501
- get('/values/array_coercion', type: [10])
502
- expect(last_response.status).to eq 200
503
- expect(last_response.body).to eq({ type: [10] }.to_json)
504
- end
505
-
506
- it 'raises IncompatibleOptionValues when values contains a value that is not a kind of the type' do
507
- subject = Class.new(Grape::API)
508
- expect do
509
- subject.params { requires :type, values: [10.5, 11], type: Integer }
510
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
511
- end
512
-
513
- it 'raises IncompatibleOptionValues when except contains a value that is not a kind of the type' do
514
- subject = Class.new(Grape::API)
515
- expect do
516
- subject.params { requires :type, values: { except: [10.5, 11] }, type: Integer }
517
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
518
- end
519
-
520
- it 'allows a blank value when the allow_blank option is true' do
521
- get 'allow_blank', name: nil
522
- expect(last_response.status).to eq(200)
523
-
524
- get 'allow_blank', name: ''
525
- expect(last_response.status).to eq(200)
526
- end
527
-
528
- context 'with a lambda values' do
529
- subject do
530
- Class.new(Grape::API) do
531
- params do
532
- optional :type, type: String, values: -> { [SecureRandom.uuid] }, default: -> { SecureRandom.uuid }
533
- end
534
- get '/random_values'
535
- end
536
- end
537
-
538
- def app
539
- subject
540
- end
541
-
542
- before do
543
- expect(SecureRandom).to receive(:uuid).and_return('foo').once
544
- end
545
-
546
- it 'only evaluates values dynamically with each request' do
547
- get '/random_values', type: 'foo'
548
- expect(last_response.status).to eq 200
549
- end
550
-
551
- it 'chooses default' do
552
- get '/random_values'
553
- expect(last_response.status).to eq 200
554
- end
555
- end
556
-
557
- context 'with a range of values' do
558
- subject(:app) do
559
- Class.new(Grape::API) do
560
- params do
561
- optional :value, type: Float, values: 0.0..10.0
562
- end
563
- get '/value' do
564
- { value: params[:value] }.to_json
565
- end
566
-
567
- params do
568
- optional :values, type: Array[Float], values: 0.0..10.0
569
- end
570
- get '/values' do
571
- { values: params[:values] }.to_json
572
- end
573
- end
574
- end
575
-
576
- it 'allows a single value inside of the range' do
577
- get('/value', value: 5.2)
578
- expect(last_response.status).to eq 200
579
- expect(last_response.body).to eq({ value: 5.2 }.to_json)
580
- end
581
-
582
- it 'allows an array of values inside of the range' do
583
- get('/values', values: [8.6, 7.5, 3, 0.9])
584
- expect(last_response.status).to eq 200
585
- expect(last_response.body).to eq({ values: [8.6, 7.5, 3.0, 0.9] }.to_json)
586
- end
587
-
588
- it 'rejects a single value outside the range' do
589
- get('/value', value: 'a')
590
- expect(last_response.status).to eq 400
591
- expect(last_response.body).to eq('value is invalid, value does not have a valid value')
592
- end
593
-
594
- it 'rejects an array of values if any of them are outside the range' do
595
- get('/values', values: [8.6, 75, 3, 0.9])
596
- expect(last_response.status).to eq 400
597
- expect(last_response.body).to eq('values does not have a valid value')
598
- end
599
- end
600
-
601
- context 'exclusive excepts' do
602
- it 'allows any other value outside excepts' do
603
- get '/except/exclusive', type: 'value'
604
- expect(last_response.status).to eq 200
605
- expect(last_response.body).to eq({ type: 'value' }.to_json)
606
- end
607
-
608
- it 'allows any other value outside excepts when type is included' do
609
- get '/except/exclusive/type', type: 'value'
610
- expect(last_response.status).to eq 200
611
- expect(last_response.body).to eq({ type: 'value' }.to_json)
612
- end
613
-
614
- it 'rejects values that matches except' do
615
- get '/except/exclusive', type: 'invalid-type1'
616
- expect(last_response.status).to eq 400
617
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
618
- end
619
-
620
- it 'rejects an array of values if any of them matches except' do
621
- get '/except/exclusive', type: %w[valid1 valid2 invalid-type1 valid4]
622
- expect(last_response.status).to eq 400
623
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
624
- end
625
- end
626
-
627
- context 'exclusive excepts with lambda' do
628
- it 'allows any other value outside excepts when type is included' do
629
- get '/except/exclusive/lambda/type', type: 'value'
630
- expect(last_response.status).to eq 200
631
- expect(last_response.body).to eq({ type: 'value' }.to_json)
632
- end
633
-
634
- it 'allows any other value outside excepts' do
635
- get '/except/exclusive/lambda', type: 'value'
636
- expect(last_response.status).to eq 200
637
- expect(last_response.body).to eq({ type: 'value' }.to_json)
638
- end
639
-
640
- it 'rejects values that matches except' do
641
- get '/except/exclusive/lambda', type: 'invalid-type1'
642
- expect(last_response.status).to eq 400
643
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
644
- end
645
- end
646
-
647
- context 'exclusive excepts with lambda and coercion' do
648
- it 'allows any other value outside excepts' do
649
- get '/except/exclusive/lambda/coercion', type: '10010000'
650
- expect(last_response.status).to eq 200
651
- expect(last_response.body).to eq({ type: 10_010_000 }.to_json)
652
- end
653
-
654
- it 'rejects values that matches except' do
655
- get '/except/exclusive/lambda/coercion', type: '3'
656
- expect(last_response.status).to eq 400
657
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
658
- end
659
- end
660
-
661
- context 'with mixed values and excepts' do
662
- it 'allows value, but not in except' do
663
- get '/mixed/value/except', type: 2
664
- expect(last_response.status).to eq 200
665
- expect(last_response.body).to eq({ type: 2 }.to_json)
666
- end
667
-
668
- it 'rejects except' do
669
- get '/mixed/value/except', type: 3
670
- expect(last_response.status).to eq 400
671
- expect(last_response.body).to eq({ error: 'type has a value not allowed' }.to_json)
672
- end
673
-
674
- it 'rejects outside except and outside value' do
675
- get '/mixed/value/except', type: 10
676
- expect(last_response.status).to eq 400
677
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
678
- end
679
- end
680
-
681
- context 'custom validation using proc' do
682
- it 'accepts a single valid value' do
683
- get '/proc', type: 'valid-type1'
684
- expect(last_response.status).to eq 200
685
- expect(last_response.body).to eq({ type: 'valid-type1' }.to_json)
686
- end
687
-
688
- it 'accepts multiple valid values' do
689
- get '/proc', type: %w[valid-type1 valid-type3]
690
- expect(last_response.status).to eq 200
691
- expect(last_response.body).to eq({ type: %w[valid-type1 valid-type3] }.to_json)
692
- end
693
-
694
- it 'rejects a single invalid value' do
695
- get '/proc', type: 'invalid-type1'
696
- expect(last_response.status).to eq 400
697
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
698
- end
699
-
700
- it 'rejects an invalid value among valid ones' do
701
- get '/proc', type: %w[valid-type1 invalid-type1 valid-type3]
702
- expect(last_response.status).to eq 400
703
- expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
704
- end
705
-
706
- it 'uses supplied message' do
707
- get '/proc/message', type: 'invalid-type1'
708
- expect(last_response.status).to eq 400
709
- expect(last_response.body).to eq({ error: 'type failed check' }.to_json)
710
- end
711
-
712
- context 'when proc has an arity of 1' do
713
- it 'accepts a valid value' do
714
- get '/proc/custom_message', number: 4
715
- expect(last_response.status).to eq 200
716
- expect(last_response.body).to eq({ message: 'success' }.to_json)
717
- end
718
-
719
- it 'rejects an invalid value' do
720
- get '/proc/custom_message', number: 5
721
- expect(last_response.status).to eq 400
722
- expect(last_response.body).to eq({ error: 'number must be even' }.to_json)
723
- end
724
- end
725
-
726
- context 'when arity is > 1' do
727
- it 'returns an error status code' do
728
- get '/proc/arity2', input_one: 2, input_two: 3
729
- expect(last_response.status).to eq 400
730
- end
731
- end
732
- end
733
- end