grape 1.8.0 → 4.0.1

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 (317) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +517 -1
  3. data/CONTRIBUTING.md +19 -11
  4. data/README.md +841 -545
  5. data/UPGRADING.md +1553 -7
  6. data/grape.gemspec +11 -14
  7. data/lib/grape/api/instance.rb +77 -160
  8. data/lib/grape/api.rb +75 -107
  9. data/lib/grape/content_types.rb +67 -9
  10. data/lib/grape/cookies.rb +28 -25
  11. data/lib/grape/declared_params_handler.rb +116 -0
  12. data/lib/grape/dry_types.rb +48 -6
  13. data/lib/grape/dsl/callbacks.rb +8 -58
  14. data/lib/grape/dsl/declared.rb +35 -0
  15. data/lib/grape/dsl/desc.rb +25 -63
  16. data/lib/grape/dsl/entity.rb +106 -0
  17. data/lib/grape/dsl/headers.rb +2 -2
  18. data/lib/grape/dsl/helpers.rb +83 -64
  19. data/lib/grape/dsl/inside_route.rb +69 -296
  20. data/lib/grape/dsl/logger.rb +4 -9
  21. data/lib/grape/dsl/middleware.rb +22 -40
  22. data/lib/grape/dsl/parameters.rb +88 -94
  23. data/lib/grape/dsl/request_response.rb +143 -147
  24. data/lib/grape/dsl/rescue_options.rb +25 -0
  25. data/lib/grape/dsl/routing.rb +333 -191
  26. data/lib/grape/dsl/settings.rb +29 -135
  27. data/lib/grape/dsl/validations.rb +39 -32
  28. data/lib/grape/dsl/version_options.rb +23 -0
  29. data/lib/grape/endpoint/options.rb +25 -0
  30. data/lib/grape/endpoint.rb +319 -269
  31. data/lib/grape/{util/env.rb → env.rb} +8 -8
  32. data/lib/grape/error_formatter/base.rb +57 -21
  33. data/lib/grape/error_formatter/json.rb +13 -15
  34. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  35. data/lib/grape/error_formatter/txt.rb +12 -18
  36. data/lib/grape/error_formatter/xml.rb +3 -13
  37. data/lib/grape/error_formatter.rb +9 -25
  38. data/lib/grape/exceptions/base.rb +22 -58
  39. data/lib/grape/exceptions/error_response.rb +48 -0
  40. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  41. data/lib/grape/exceptions/internal_server_error.rb +16 -0
  42. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  43. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  44. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  45. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  46. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  47. data/lib/grape/exceptions/method_not_allowed.rb +1 -1
  48. data/lib/grape/exceptions/missing_group_type.rb +0 -2
  49. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  50. data/lib/grape/exceptions/request_error.rb +11 -0
  51. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  52. data/lib/grape/exceptions/unknown_error_formatter.rb +11 -0
  53. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  54. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  55. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  56. data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
  57. data/lib/grape/exceptions/validation.rb +28 -11
  58. data/lib/grape/exceptions/validation_array_errors.rb +5 -0
  59. data/lib/grape/exceptions/validation_errors.rb +22 -26
  60. data/lib/grape/formatter/base.rb +16 -0
  61. data/lib/grape/formatter/json.rb +5 -6
  62. data/lib/grape/formatter/serializable_hash.rb +7 -10
  63. data/lib/grape/formatter/txt.rb +3 -5
  64. data/lib/grape/formatter/xml.rb +4 -6
  65. data/lib/grape/formatter.rb +7 -25
  66. data/lib/grape/json.rb +46 -0
  67. data/lib/grape/locale/en.yml +44 -42
  68. data/lib/grape/middleware/auth/base.rb +11 -33
  69. data/lib/grape/middleware/auth/dsl.rb +12 -34
  70. data/lib/grape/middleware/auth/strategies.rb +1 -2
  71. data/lib/grape/middleware/base.rb +56 -33
  72. data/lib/grape/middleware/error.rb +290 -91
  73. data/lib/grape/middleware/formatter.rb +164 -106
  74. data/lib/grape/middleware/precomputed_content_types.rb +51 -0
  75. data/lib/grape/middleware/stack.rb +38 -40
  76. data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
  77. data/lib/grape/middleware/versioner/base.rb +66 -0
  78. data/lib/grape/middleware/versioner/header.rb +44 -129
  79. data/lib/grape/middleware/versioner/param.rb +4 -25
  80. data/lib/grape/middleware/versioner/path.rb +48 -25
  81. data/lib/grape/middleware/versioner.rb +7 -14
  82. data/lib/grape/mountable.rb +22 -0
  83. data/lib/grape/namespace.rb +21 -14
  84. data/lib/grape/params_builder/base.rb +20 -0
  85. data/lib/grape/params_builder/hash.rb +11 -0
  86. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  87. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  88. data/lib/grape/params_builder.rb +15 -0
  89. data/lib/grape/parser/base.rb +16 -0
  90. data/lib/grape/parser/json.rb +6 -8
  91. data/lib/grape/parser/xml.rb +6 -8
  92. data/lib/grape/parser.rb +5 -23
  93. data/lib/grape/path.rb +8 -94
  94. data/lib/grape/precompiled_json.rb +50 -0
  95. data/lib/grape/railtie.rb +9 -0
  96. data/lib/grape/request.rb +200 -26
  97. data/lib/grape/router/base_route.rb +85 -0
  98. data/lib/grape/router/greedy_route.rb +30 -0
  99. data/lib/grape/router/mustermann_pattern.rb +44 -0
  100. data/lib/grape/router/pattern/path.rb +78 -0
  101. data/lib/grape/router/pattern.rb +77 -35
  102. data/lib/grape/router/route.rb +79 -60
  103. data/lib/grape/router.rb +128 -104
  104. data/lib/grape/serve_stream/file_body.rb +7 -0
  105. data/lib/grape/serve_stream/sendfile_response.rb +3 -5
  106. data/lib/grape/serve_stream/stream_response.rb +7 -0
  107. data/lib/grape/testing.rb +33 -0
  108. data/lib/grape/util/api_description.rb +67 -0
  109. data/lib/grape/util/cache.rb +22 -5
  110. data/lib/grape/util/deep_freeze.rb +34 -0
  111. data/lib/grape/util/endpoint_configuration.rb +1 -1
  112. data/lib/grape/util/freeze_on_new.rb +20 -0
  113. data/lib/grape/util/header.rb +13 -0
  114. data/lib/grape/util/inheritable_setting.rb +777 -39
  115. data/lib/grape/util/lazy/base.rb +16 -0
  116. data/lib/grape/util/lazy/block.rb +22 -0
  117. data/lib/grape/util/lazy/value.rb +31 -0
  118. data/lib/grape/util/lazy/value_array.rb +21 -0
  119. data/lib/grape/util/lazy/value_enumerable.rb +31 -0
  120. data/lib/grape/util/lazy/value_hash.rb +21 -0
  121. data/lib/grape/util/media_type.rb +74 -0
  122. data/lib/grape/util/path_normalizer.rb +37 -0
  123. data/lib/grape/util/registry.rb +37 -0
  124. data/lib/grape/util/shadowed_rescue_handlers.rb +49 -0
  125. data/lib/grape/util/stackable_values.rb +40 -16
  126. data/lib/grape/util/translation.rb +42 -0
  127. data/lib/grape/validations/attributes_iterator.rb +61 -28
  128. data/lib/grape/validations/coerce_options.rb +21 -0
  129. data/lib/grape/validations/contract_scope.rb +29 -0
  130. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  131. data/lib/grape/validations/oneof_collector.rb +35 -0
  132. data/lib/grape/validations/param_scope_tracker.rb +62 -0
  133. data/lib/grape/validations/params_documentation.rb +52 -0
  134. data/lib/grape/validations/params_scope.rb +223 -306
  135. data/lib/grape/validations/shared_options.rb +19 -0
  136. data/lib/grape/validations/single_attribute_iterator.rb +6 -4
  137. data/lib/grape/validations/types/array_coercer.rb +7 -12
  138. data/lib/grape/validations/types/custom_type_coercer.rb +47 -85
  139. data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
  140. data/lib/grape/validations/types/dry_type_coercer.rb +17 -28
  141. data/lib/grape/validations/types/json.rb +1 -5
  142. data/lib/grape/validations/types/multiple_type_coercer.rb +5 -3
  143. data/lib/grape/validations/types/primitive_coercer.rb +14 -35
  144. data/lib/grape/validations/types/set_coercer.rb +1 -4
  145. data/lib/grape/validations/types/variant_collection_coercer.rb +16 -3
  146. data/lib/grape/validations/types.rb +29 -54
  147. data/lib/grape/validations/validations_spec.rb +164 -0
  148. data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
  149. data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
  150. data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
  151. data/lib/grape/validations/validators/base.rb +118 -37
  152. data/lib/grape/validations/validators/coerce_validator.rb +26 -38
  153. data/lib/grape/validations/validators/contract_scope_validator.rb +46 -0
  154. data/lib/grape/validations/validators/default_validator.rb +13 -16
  155. data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
  156. data/lib/grape/validations/validators/except_values_validator.rb +15 -5
  157. data/lib/grape/validations/validators/length_validator.rb +50 -0
  158. data/lib/grape/validations/validators/multiple_params_base.rb +12 -9
  159. data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
  160. data/lib/grape/validations/validators/oneof_validator.rb +51 -0
  161. data/lib/grape/validations/validators/presence_validator.rb +4 -2
  162. data/lib/grape/validations/validators/regexp_validator.rb +11 -3
  163. data/lib/grape/validations/validators/same_as_validator.rb +7 -15
  164. data/lib/grape/validations/validators/values_validator.rb +36 -65
  165. data/lib/grape/validations.rb +8 -21
  166. data/lib/grape/version.rb +1 -2
  167. data/lib/grape/xml.rb +17 -0
  168. data/lib/grape.rb +96 -288
  169. metadata +83 -294
  170. data/lib/grape/api/helpers.rb +0 -9
  171. data/lib/grape/dsl/api.rb +0 -19
  172. data/lib/grape/dsl/configuration.rb +0 -15
  173. data/lib/grape/eager_load.rb +0 -20
  174. data/lib/grape/exceptions/empty_message_body.rb +0 -11
  175. data/lib/grape/exceptions/missing_option.rb +0 -11
  176. data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
  177. data/lib/grape/exceptions/unknown_options.rb +0 -11
  178. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +0 -27
  179. data/lib/grape/extensions/hash.rb +0 -22
  180. data/lib/grape/extensions/hashie/mash.rb +0 -26
  181. data/lib/grape/http/headers.rb +0 -61
  182. data/lib/grape/middleware/globals.rb +0 -16
  183. data/lib/grape/middleware/helpers.rb +0 -12
  184. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  185. data/lib/grape/router/attribute_translator.rb +0 -63
  186. data/lib/grape/types/invalid_value.rb +0 -8
  187. data/lib/grape/util/base_inheritable.rb +0 -43
  188. data/lib/grape/util/inheritable_values.rb +0 -31
  189. data/lib/grape/util/json.rb +0 -12
  190. data/lib/grape/util/lazy_block.rb +0 -27
  191. data/lib/grape/util/lazy_object.rb +0 -43
  192. data/lib/grape/util/lazy_value.rb +0 -91
  193. data/lib/grape/util/registrable.rb +0 -15
  194. data/lib/grape/util/reverse_stackable_values.rb +0 -20
  195. data/lib/grape/util/strict_hash_configuration.rb +0 -108
  196. data/lib/grape/util/xml.rb +0 -10
  197. data/lib/grape/validations/attributes_doc.rb +0 -58
  198. data/lib/grape/validations/types/build_coercer.rb +0 -94
  199. data/lib/grape/validations/validator_factory.rb +0 -15
  200. data/spec/grape/api/custom_validations_spec.rb +0 -213
  201. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  202. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  203. data/spec/grape/api/documentation_spec.rb +0 -59
  204. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  205. data/spec/grape/api/instance_spec.rb +0 -103
  206. data/spec/grape/api/invalid_format_spec.rb +0 -45
  207. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  208. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  209. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  210. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  211. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  212. data/spec/grape/api/recognize_path_spec.rb +0 -21
  213. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  214. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  215. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  216. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  217. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  218. data/spec/grape/api_remount_spec.rb +0 -509
  219. data/spec/grape/api_spec.rb +0 -4356
  220. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  221. data/spec/grape/dsl/desc_spec.rb +0 -98
  222. data/spec/grape/dsl/headers_spec.rb +0 -62
  223. data/spec/grape/dsl/helpers_spec.rb +0 -100
  224. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  225. data/spec/grape/dsl/logger_spec.rb +0 -24
  226. data/spec/grape/dsl/middleware_spec.rb +0 -60
  227. data/spec/grape/dsl/parameters_spec.rb +0 -180
  228. data/spec/grape/dsl/request_response_spec.rb +0 -225
  229. data/spec/grape/dsl/routing_spec.rb +0 -275
  230. data/spec/grape/dsl/settings_spec.rb +0 -261
  231. data/spec/grape/dsl/validations_spec.rb +0 -55
  232. data/spec/grape/endpoint/declared_spec.rb +0 -846
  233. data/spec/grape/endpoint_spec.rb +0 -1085
  234. data/spec/grape/entity_spec.rb +0 -336
  235. data/spec/grape/exceptions/base_spec.rb +0 -81
  236. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  237. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  238. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  239. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  240. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  241. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  242. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  243. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  244. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  245. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  246. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  247. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  248. data/spec/grape/exceptions/validation_spec.rb +0 -19
  249. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  250. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  251. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  252. data/spec/grape/grape_spec.rb +0 -9
  253. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  254. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  255. data/spec/grape/integration/rack_spec.rb +0 -51
  256. data/spec/grape/loading_spec.rb +0 -44
  257. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  258. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  259. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  260. data/spec/grape/middleware/base_spec.rb +0 -221
  261. data/spec/grape/middleware/error_spec.rb +0 -85
  262. data/spec/grape/middleware/exception_spec.rb +0 -294
  263. data/spec/grape/middleware/formatter_spec.rb +0 -461
  264. data/spec/grape/middleware/globals_spec.rb +0 -30
  265. data/spec/grape/middleware/stack_spec.rb +0 -155
  266. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  267. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  268. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  269. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  270. data/spec/grape/middleware/versioner_spec.rb +0 -21
  271. data/spec/grape/named_api_spec.rb +0 -19
  272. data/spec/grape/parser_spec.rb +0 -86
  273. data/spec/grape/path_spec.rb +0 -252
  274. data/spec/grape/presenters/presenter_spec.rb +0 -71
  275. data/spec/grape/request_spec.rb +0 -126
  276. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  277. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  278. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  279. data/spec/grape/util/stackable_values_spec.rb +0 -128
  280. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  281. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  282. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  283. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  284. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  285. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  286. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  287. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  288. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  289. data/spec/grape/validations/types_spec.rb +0 -111
  290. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  291. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  292. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  293. data/spec/grape/validations/validators/base_spec.rb +0 -38
  294. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  295. data/spec/grape/validations/validators/default_spec.rb +0 -463
  296. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  297. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  298. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  299. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  300. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  301. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  302. data/spec/grape/validations/validators/values_spec.rb +0 -733
  303. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  304. data/spec/grape/validations_spec.rb +0 -2030
  305. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  306. data/spec/integration/multi_json/json_spec.rb +0 -7
  307. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  308. data/spec/shared/deprecated_class_examples.rb +0 -16
  309. data/spec/shared/versioning_examples.rb +0 -215
  310. data/spec/spec_helper.rb +0 -52
  311. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  312. data/spec/support/chunks.rb +0 -14
  313. data/spec/support/content_type_helpers.rb +0 -15
  314. data/spec/support/endpoint_faker.rb +0 -25
  315. data/spec/support/file_streamer.rb +0 -13
  316. data/spec/support/integer_helpers.rb +0 -13
  317. data/spec/support/versioned_helpers.rb +0 -55
@@ -1,192 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::ExceptValuesValidator do
4
- module ValidationsSpec
5
- class ExceptValuesModel
6
- DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze
7
- class << self
8
- attr_accessor :excepts
9
-
10
- def excepts
11
- @excepts ||= []
12
- [DEFAULT_EXCEPTS + @excepts].flatten.uniq
13
- end
14
- end
15
- end
16
-
17
- TEST_CASES = {
18
- req_except: {
19
- requires: { except_values: ExceptValuesModel.excepts },
20
- tests: [
21
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
22
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
23
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
24
- ]
25
- },
26
- req_except_hash: {
27
- requires: { except_values: { value: ExceptValuesModel.excepts } },
28
- tests: [
29
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
30
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
31
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
32
- ]
33
- },
34
- req_except_custom_message: {
35
- requires: { except_values: { value: ExceptValuesModel.excepts, message: 'is not allowed' } },
36
- tests: [
37
- { value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
38
- { value: 'invalid-type3', rc: 400, body: { error: 'type is not allowed' }.to_json },
39
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
40
- ]
41
- },
42
- req_except_no_value: {
43
- requires: { except_values: { message: 'is not allowed' } },
44
- tests: [
45
- { value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
46
- ]
47
- },
48
- req_except_empty: {
49
- requires: { except_values: [] },
50
- tests: [
51
- { value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
52
- ]
53
- },
54
- req_except_lambda: {
55
- requires: { except_values: -> { ExceptValuesModel.excepts } },
56
- add_excepts: ['invalid-type4'],
57
- tests: [
58
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
59
- { value: 'invalid-type4', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
60
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
61
- ]
62
- },
63
- req_except_lambda_custom_message: {
64
- requires: { except_values: { value: -> { ExceptValuesModel.excepts }, message: 'is not allowed' } },
65
- add_excepts: ['invalid-type4'],
66
- tests: [
67
- { value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
68
- { value: 'invalid-type4', rc: 400, body: { error: 'type is not allowed' }.to_json },
69
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
70
- ]
71
- },
72
- opt_except_default: {
73
- optional: { except_values: ExceptValuesModel.excepts, default: 'valid-type2' },
74
- tests: [
75
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
76
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
77
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
78
- { rc: 200, body: { type: 'valid-type2' }.to_json }
79
- ]
80
- },
81
- opt_except_lambda_default: {
82
- optional: { except_values: -> { ExceptValuesModel.excepts }, default: 'valid-type2' },
83
- tests: [
84
- { value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
85
- { value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
86
- { value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
87
- { rc: 200, body: { type: 'valid-type2' }.to_json }
88
- ]
89
- },
90
- req_except_type_coerce: {
91
- requires: { type: Integer, except_values: [10, 11] },
92
- tests: [
93
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
94
- { value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
95
- { value: '11', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
96
- { value: '3', rc: 200, body: { type: 3 }.to_json },
97
- { value: 3, rc: 200, body: { type: 3 }.to_json }
98
- ]
99
- },
100
- opt_except_type_coerce_default: {
101
- optional: { type: Integer, except_values: [10, 11], default: 12 },
102
- tests: [
103
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
104
- { value: 10, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
105
- { value: '3', rc: 200, body: { type: 3 }.to_json },
106
- { value: 3, rc: 200, body: { type: 3 }.to_json },
107
- { rc: 200, body: { type: 12 }.to_json }
108
- ]
109
- },
110
- opt_except_array_type_coerce_default: {
111
- optional: { type: Array[Integer], except_values: [10, 11], default: 12 },
112
- tests: [
113
- { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
114
- { value: 10, rc: 400, body: { error: 'type is invalid' }.to_json },
115
- { value: [10], rc: 400, body: { error: 'type has a value not allowed' }.to_json },
116
- { value: ['3'], rc: 200, body: { type: [3] }.to_json },
117
- { value: [3], rc: 200, body: { type: [3] }.to_json },
118
- { rc: 200, body: { type: 12 }.to_json }
119
- ]
120
- },
121
- req_except_range: {
122
- optional: { type: Integer, except_values: 10..12 },
123
- tests: [
124
- { value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
125
- { value: 13, rc: 200, body: { type: 13 }.to_json }
126
- ]
127
- }
128
- }.freeze
129
-
130
- module ExceptValidatorSpec
131
- class API < Grape::API
132
- default_format :json
133
-
134
- TEST_CASES.each_with_index do |(k, v), _i|
135
- params do
136
- requires :type, v[:requires] if v.key? :requires
137
- optional :type, v[:optional] if v.key? :optional
138
- end
139
- get k do
140
- { type: params[:type] }
141
- end
142
- end
143
- end
144
- end
145
- end
146
-
147
- it 'raises IncompatibleOptionValues on a default value in exclude' do
148
- subject = Class.new(Grape::API)
149
- expect do
150
- subject.params do
151
- optional :type, except_values: ValidationsSpec::ExceptValuesModel.excepts,
152
- default: ValidationsSpec::ExceptValuesModel.excepts.sample
153
- end
154
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
155
- end
156
-
157
- it 'raises IncompatibleOptionValues when a default array has excluded values' do
158
- subject = Class.new(Grape::API)
159
- expect do
160
- subject.params do
161
- optional :type, type: Array[Integer],
162
- except_values: 10..12,
163
- default: [8, 9, 10]
164
- end
165
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
166
- end
167
-
168
- it 'raises IncompatibleOptionValues when type is incompatible with values array' do
169
- subject = Class.new(Grape::API)
170
- expect do
171
- subject.params { optional :type, except_values: %w[valid-type1 valid-type2 valid-type3], type: Symbol }
172
- end.to raise_error Grape::Exceptions::IncompatibleOptionValues
173
- end
174
-
175
- def app
176
- ValidationsSpec::ExceptValidatorSpec::API
177
- end
178
-
179
- ValidationsSpec::TEST_CASES.each_with_index do |(k, v), i|
180
- v[:tests].each do |t|
181
- it "#{i}: #{k} - #{t[:value]}" do
182
- ValidationsSpec::ExceptValuesModel.excepts = v[:add_excepts] if v.key? :add_excepts
183
- body = {}
184
- body[:type] = t[:value] if t.key? :value
185
- get k.to_s, **body
186
- expect(last_response.status).to eq t[:rc]
187
- expect(last_response.body).to eq t[:body]
188
- ValidationsSpec::ExceptValuesModel.excepts = nil
189
- end
190
- end
191
- end
192
- end
@@ -1,214 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::MutualExclusionValidator do
4
- let_it_be(:app) do
5
- Class.new(Grape::API) do
6
- rescue_from Grape::Exceptions::ValidationErrors do |e|
7
- error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
8
- end
9
-
10
- params do
11
- optional :beer
12
- optional :wine
13
- optional :grapefruit
14
- mutually_exclusive :beer, :wine, :grapefruit
15
- end
16
- post do
17
- end
18
-
19
- params do
20
- optional :beer
21
- optional :wine
22
- optional :grapefruit
23
- optional :other
24
- mutually_exclusive :beer, :wine, :grapefruit
25
- end
26
- post 'mixed-params' do
27
- end
28
-
29
- params do
30
- optional :beer
31
- optional :wine
32
- optional :grapefruit
33
- mutually_exclusive :beer, :wine, :grapefruit, message: 'you should not mix beer and wine'
34
- end
35
- post '/custom-message' do
36
- end
37
-
38
- params do
39
- requires :item, type: Hash do
40
- optional :beer
41
- optional :wine
42
- optional :grapefruit
43
- mutually_exclusive :beer, :wine, :grapefruit
44
- end
45
- end
46
- post '/nested-hash' do
47
- end
48
-
49
- params do
50
- optional :item, type: Hash do
51
- optional :beer
52
- optional :wine
53
- optional :grapefruit
54
- mutually_exclusive :beer, :wine, :grapefruit
55
- end
56
- end
57
- post '/nested-optional-hash' do
58
- end
59
-
60
- params do
61
- requires :items, type: Array do
62
- optional :beer
63
- optional :wine
64
- optional :grapefruit
65
- mutually_exclusive :beer, :wine, :grapefruit
66
- end
67
- end
68
- post '/nested-array' do
69
- end
70
-
71
- params do
72
- requires :items, type: Array do
73
- requires :nested_items, type: Array do
74
- optional :beer, :wine, :grapefruit, type: Grape::API::Boolean
75
- mutually_exclusive :beer, :wine, :grapefruit
76
- end
77
- end
78
- end
79
- post '/deeply-nested-array' do
80
- end
81
- end
82
- end
83
-
84
- describe '#validate!' do
85
- subject(:validate) { post path, params }
86
-
87
- context 'when all mutually exclusive params are present' do
88
- let(:path) { '/' }
89
- let(:params) { { beer: true, wine: true, grapefruit: true } }
90
-
91
- it 'returns a validation error' do
92
- validate
93
- expect(last_response.status).to eq 400
94
- expect(JSON.parse(last_response.body)).to eq(
95
- 'beer,wine,grapefruit' => ['are mutually exclusive']
96
- )
97
- end
98
-
99
- context 'mixed with other params' do
100
- let(:path) { '/mixed-params' }
101
- let(:params) { { beer: true, wine: true, grapefruit: true, other: true } }
102
-
103
- it 'returns a validation error' do
104
- validate
105
- expect(last_response.status).to eq 400
106
- expect(JSON.parse(last_response.body)).to eq(
107
- 'beer,wine,grapefruit' => ['are mutually exclusive']
108
- )
109
- end
110
- end
111
- end
112
-
113
- context 'when a subset of mutually exclusive params are present' do
114
- let(:path) { '/' }
115
- let(:params) { { beer: true, grapefruit: true } }
116
-
117
- it 'returns a validation error' do
118
- validate
119
- expect(last_response.status).to eq 400
120
- expect(JSON.parse(last_response.body)).to eq(
121
- 'beer,grapefruit' => ['are mutually exclusive']
122
- )
123
- end
124
- end
125
-
126
- context 'when custom message is specified' do
127
- let(:path) { '/custom-message' }
128
- let(:params) { { beer: true, wine: true } }
129
-
130
- it 'returns a validation error' do
131
- validate
132
- expect(last_response.status).to eq 400
133
- expect(JSON.parse(last_response.body)).to eq(
134
- 'beer,wine' => ['you should not mix beer and wine']
135
- )
136
- end
137
- end
138
-
139
- context 'when no mutually exclusive params are present' do
140
- let(:path) { '/' }
141
- let(:params) { { beer: true, somethingelse: true } }
142
-
143
- it 'does not return a validation error' do
144
- validate
145
- expect(last_response.status).to eq 201
146
- end
147
- end
148
-
149
- context 'when mutually exclusive params are nested inside required hash' do
150
- let(:path) { '/nested-hash' }
151
- let(:params) { { item: { beer: true, wine: true } } }
152
-
153
- it 'returns a validation error with full names of the params' do
154
- validate
155
- expect(last_response.status).to eq 400
156
- expect(JSON.parse(last_response.body)).to eq(
157
- 'item[beer],item[wine]' => ['are mutually exclusive']
158
- )
159
- end
160
- end
161
-
162
- context 'when mutually exclusive params are nested inside optional hash' do
163
- let(:path) { '/nested-optional-hash' }
164
-
165
- context 'when params are passed' do
166
- let(:params) { { item: { beer: true, wine: true } } }
167
-
168
- it 'returns a validation error with full names of the params' do
169
- validate
170
- expect(last_response.status).to eq 400
171
- expect(JSON.parse(last_response.body)).to eq(
172
- 'item[beer],item[wine]' => ['are mutually exclusive']
173
- )
174
- end
175
- end
176
-
177
- context 'when params are empty' do
178
- let(:params) { {} }
179
-
180
- it 'does not return a validation error' do
181
- validate
182
- expect(last_response.status).to eq 201
183
- end
184
- end
185
- end
186
-
187
- context 'when mutually exclusive params are nested inside array' do
188
- let(:path) { '/nested-array' }
189
- let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
190
-
191
- it 'returns a validation error with full names of the params' do
192
- validate
193
- expect(last_response.status).to eq 400
194
- expect(JSON.parse(last_response.body)).to eq(
195
- 'items[0][beer],items[0][wine]' => ['are mutually exclusive'],
196
- 'items[1][wine],items[1][grapefruit]' => ['are mutually exclusive']
197
- )
198
- end
199
- end
200
-
201
- context 'when mutually exclusive params are deeply nested' do
202
- let(:path) { '/deeply-nested-array' }
203
- let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
204
-
205
- it 'returns a validation error with full names of the params' do
206
- validate
207
- expect(last_response.status).to eq 400
208
- expect(JSON.parse(last_response.body)).to eq(
209
- 'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => ['are mutually exclusive']
210
- )
211
- end
212
- end
213
- end
214
- end