grape 1.3.3 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +111 -2
- data/CONTRIBUTING.md +2 -1
- data/README.md +135 -23
- data/UPGRADING.md +237 -46
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +34 -42
- data/lib/grape/api.rb +21 -16
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +1 -1
- data/lib/grape/dsl/desc.rb +3 -5
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +8 -5
- data/lib/grape/dsl/inside_route.rb +72 -53
- data/lib/grape/dsl/middleware.rb +4 -4
- data/lib/grape/dsl/parameters.rb +11 -7
- data/lib/grape/dsl/request_response.rb +9 -6
- data/lib/grape/dsl/routing.rb +8 -9
- data/lib/grape/dsl/settings.rb +5 -5
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +29 -42
- data/lib/grape/error_formatter/json.rb +2 -6
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/validation.rb +2 -3
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/base.rb +3 -3
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +6 -3
- data/lib/grape/middleware/error.rb +11 -13
- data/lib/grape/middleware/formatter.rb +7 -7
- data/lib/grape/middleware/stack.rb +10 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +4 -1
- data/lib/grape/router/attribute_translator.rb +3 -3
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +31 -30
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +2 -2
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/lazy_value.rb +4 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_iterator.rb +8 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +97 -62
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +4 -5
- data/lib/grape/validations/types.rb +1 -4
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/all_or_none.rb +8 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +6 -8
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
- data/lib/grape/validations/validators/base.rb +74 -69
- data/lib/grape/validations/validators/coerce.rb +63 -76
- data/lib/grape/validations/validators/default.rb +36 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
- data/lib/grape/validations/validators/presence.rb +7 -4
- data/lib/grape/validations/validators/regexp.rb +8 -5
- data/lib/grape/validations/validators/same_as.rb +18 -15
- data/lib/grape/validations/validators/values.rb +61 -56
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +7 -3
- data/spec/grape/api/custom_validations_spec.rb +77 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -3
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +1 -1
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +25 -19
- data/spec/grape/api_spec.rb +576 -211
- data/spec/grape/dsl/callbacks_spec.rb +2 -1
- data/spec/grape/dsl/headers_spec.rb +39 -9
- data/spec/grape/dsl/helpers_spec.rb +3 -2
- data/spec/grape/dsl/inside_route_spec.rb +185 -34
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +2 -1
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +10 -7
- data/spec/grape/endpoint/declared_spec.rb +848 -0
- data/spec/grape/endpoint_spec.rb +77 -589
- data/spec/grape/entity_spec.rb +29 -23
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
- data/spec/grape/exceptions/validation_spec.rb +5 -3
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
- data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
- data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +3 -3
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +28 -7
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +15 -12
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
- data/spec/grape/middleware/versioner/header_spec.rb +14 -13
- data/spec/grape/middleware/versioner/param_spec.rb +7 -1
- data/spec/grape/middleware/versioner/path_spec.rb +5 -1
- data/spec/grape/middleware/versioner_spec.rb +1 -1
- data/spec/grape/parser_spec.rb +4 -0
- data/spec/grape/path_spec.rb +52 -52
- data/spec/grape/presenters/presenter_spec.rb +7 -6
- data/spec/grape/request_spec.rb +6 -4
- data/spec/grape/util/inheritable_setting_spec.rb +7 -7
- data/spec/grape/util/inheritable_values_spec.rb +3 -2
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
- data/spec/grape/util/stackable_values_spec.rb +7 -5
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
- data/spec/grape/validations/params_scope_spec.rb +72 -10
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
- data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
- data/spec/grape/validations/types_spec.rb +8 -8
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
- data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
- data/spec/grape/validations/validators/coerce_spec.rb +248 -33
- data/spec/grape/validations/validators/default_spec.rb +121 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +4 -3
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
- data/spec/grape/validations/validators/presence_spec.rb +16 -1
- data/spec/grape/validations/validators/regexp_spec.rb +25 -31
- data/spec/grape/validations/validators/same_as_spec.rb +14 -20
- data/spec/grape/validations/validators/values_spec.rb +183 -178
- data/spec/grape/validations_spec.rb +342 -29
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +1 -1
- data/spec/integration/multi_xml/xml_spec.rb +1 -1
- data/spec/shared/versioning_examples.rb +32 -29
- data/spec/spec_helper.rb +12 -12
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +4 -6
- metadata +110 -102
@@ -9,6 +9,10 @@ describe Grape::Validations do
|
|
9
9
|
subject
|
10
10
|
end
|
11
11
|
|
12
|
+
def declared_params
|
13
|
+
subject.namespace_stackable(:declared_params).flatten
|
14
|
+
end
|
15
|
+
|
12
16
|
describe 'params' do
|
13
17
|
context 'optional' do
|
14
18
|
before do
|
@@ -41,7 +45,7 @@ describe Grape::Validations do
|
|
41
45
|
subject.params do
|
42
46
|
optional :some_param
|
43
47
|
end
|
44
|
-
expect(
|
48
|
+
expect(declared_params).to eq([:some_param])
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -61,7 +65,7 @@ describe Grape::Validations do
|
|
61
65
|
|
62
66
|
it 'adds entity documentation to declared params' do
|
63
67
|
define_optional_using
|
64
|
-
expect(
|
68
|
+
expect(declared_params).to eq(%i[field_a field_b])
|
65
69
|
end
|
66
70
|
|
67
71
|
it 'works when field_a and field_b are not present' do
|
@@ -108,7 +112,7 @@ describe Grape::Validations do
|
|
108
112
|
subject.params do
|
109
113
|
requires :some_param
|
110
114
|
end
|
111
|
-
expect(
|
115
|
+
expect(declared_params).to eq([:some_param])
|
112
116
|
end
|
113
117
|
|
114
118
|
it 'works when required field is present but nil' do
|
@@ -193,7 +197,7 @@ describe Grape::Validations do
|
|
193
197
|
|
194
198
|
it 'adds entity documentation to declared params' do
|
195
199
|
define_requires_all
|
196
|
-
expect(
|
200
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
197
201
|
end
|
198
202
|
|
199
203
|
it 'errors when required_field is not present' do
|
@@ -228,7 +232,7 @@ describe Grape::Validations do
|
|
228
232
|
|
229
233
|
it 'adds entity documentation to declared params' do
|
230
234
|
define_requires_none
|
231
|
-
expect(
|
235
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
232
236
|
end
|
233
237
|
|
234
238
|
it 'errors when required_field is not present' do
|
@@ -258,7 +262,7 @@ describe Grape::Validations do
|
|
258
262
|
|
259
263
|
it 'adds only the entity documentation to declared params, nothing more' do
|
260
264
|
define_requires_all
|
261
|
-
expect(
|
265
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
262
266
|
end
|
263
267
|
end
|
264
268
|
|
@@ -324,7 +328,7 @@ describe Grape::Validations do
|
|
324
328
|
requires :key
|
325
329
|
end
|
326
330
|
end
|
327
|
-
expect(
|
331
|
+
expect(declared_params).to eq([items: [:key]])
|
328
332
|
end
|
329
333
|
end
|
330
334
|
|
@@ -396,7 +400,7 @@ describe Grape::Validations do
|
|
396
400
|
requires :key
|
397
401
|
end
|
398
402
|
end
|
399
|
-
expect(
|
403
|
+
expect(declared_params).to eq([items: [:key]])
|
400
404
|
end
|
401
405
|
end
|
402
406
|
|
@@ -459,7 +463,7 @@ describe Grape::Validations do
|
|
459
463
|
requires :key
|
460
464
|
end
|
461
465
|
end
|
462
|
-
expect(
|
466
|
+
expect(declared_params).to eq([items: [:key]])
|
463
467
|
end
|
464
468
|
end
|
465
469
|
|
@@ -485,17 +489,24 @@ describe Grape::Validations do
|
|
485
489
|
end
|
486
490
|
|
487
491
|
context 'custom validator for a Hash' do
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
end
|
492
|
+
let(:date_range_validator) do
|
493
|
+
Class.new(Grape::Validations::Validators::Base) do
|
494
|
+
def validate_param!(attr_name, params)
|
495
|
+
return if params[attr_name][:from] <= params[attr_name][:to]
|
496
|
+
|
497
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'")
|
495
498
|
end
|
496
499
|
end
|
497
500
|
end
|
498
501
|
|
502
|
+
before do
|
503
|
+
described_class.register_validator('date_range', date_range_validator)
|
504
|
+
end
|
505
|
+
|
506
|
+
after do
|
507
|
+
described_class.deregister_validator('date_range')
|
508
|
+
end
|
509
|
+
|
499
510
|
before do
|
500
511
|
subject.params do
|
501
512
|
optional :date_range, date_range: true, type: Hash do
|
@@ -813,7 +824,7 @@ describe Grape::Validations do
|
|
813
824
|
requires :key
|
814
825
|
end
|
815
826
|
end
|
816
|
-
expect(
|
827
|
+
expect(declared_params).to eq([items: [:key]])
|
817
828
|
end
|
818
829
|
end
|
819
830
|
|
@@ -877,7 +888,284 @@ describe Grape::Validations do
|
|
877
888
|
requires(:required_subitems, type: Array) { requires :value }
|
878
889
|
end
|
879
890
|
end
|
880
|
-
expect(
|
891
|
+
expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
|
892
|
+
end
|
893
|
+
|
894
|
+
context <<~DESC do
|
895
|
+
Issue occurs whenever:
|
896
|
+
* param structure with at least three levels
|
897
|
+
* 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing#{' '}
|
898
|
+
* 2nd level is an optional Array or Hash#{' '}
|
899
|
+
* 3rd level is a required item (can be any type)
|
900
|
+
* additional levels do not effect the issue from occuring
|
901
|
+
DESC
|
902
|
+
|
903
|
+
it 'example based off actual real world use case' do
|
904
|
+
subject.params do
|
905
|
+
requires :orders, type: Array do
|
906
|
+
requires :id, type: Integer
|
907
|
+
optional :drugs, type: Array do
|
908
|
+
requires :batches, type: Array do
|
909
|
+
requires :batch_no, type: String
|
910
|
+
end
|
911
|
+
end
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
916
|
+
'validate_required_arrays_under_optional_arrays works!'
|
917
|
+
end
|
918
|
+
|
919
|
+
data = {
|
920
|
+
orders: [
|
921
|
+
{ id: 77, drugs: [{ batches: [{ batch_no: 'A1234567' }] }] },
|
922
|
+
{ id: 70 }
|
923
|
+
]
|
924
|
+
}
|
925
|
+
|
926
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
927
|
+
expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
|
928
|
+
expect(last_response.status).to eq(200)
|
929
|
+
end
|
930
|
+
|
931
|
+
it 'simplest example using Array -> Array -> Hash -> String' do
|
932
|
+
subject.params do
|
933
|
+
requires :orders, type: Array do
|
934
|
+
requires :id, type: Integer
|
935
|
+
optional :drugs, type: Array do
|
936
|
+
requires :batch_no, type: String
|
937
|
+
end
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
942
|
+
'validate_required_arrays_under_optional_arrays works!'
|
943
|
+
end
|
944
|
+
|
945
|
+
data = {
|
946
|
+
orders: [
|
947
|
+
{ id: 77, drugs: [{ batch_no: 'A1234567' }] },
|
948
|
+
{ id: 70 }
|
949
|
+
]
|
950
|
+
}
|
951
|
+
|
952
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
953
|
+
expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
|
954
|
+
expect(last_response.status).to eq(200)
|
955
|
+
end
|
956
|
+
|
957
|
+
it 'simplest example using Array -> Hash -> String' do
|
958
|
+
subject.params do
|
959
|
+
requires :orders, type: Array do
|
960
|
+
requires :id, type: Integer
|
961
|
+
optional :drugs, type: Hash do
|
962
|
+
requires :batch_no, type: String
|
963
|
+
end
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
968
|
+
'validate_required_arrays_under_optional_arrays works!'
|
969
|
+
end
|
970
|
+
|
971
|
+
data = {
|
972
|
+
orders: [
|
973
|
+
{ id: 77, drugs: { batch_no: 'A1234567' } },
|
974
|
+
{ id: 70 }
|
975
|
+
]
|
976
|
+
}
|
977
|
+
|
978
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
979
|
+
expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
|
980
|
+
expect(last_response.status).to eq(200)
|
981
|
+
end
|
982
|
+
|
983
|
+
it 'correctly indexes invalida data' do
|
984
|
+
subject.params do
|
985
|
+
requires :orders, type: Array do
|
986
|
+
requires :id, type: Integer
|
987
|
+
optional :drugs, type: Array do
|
988
|
+
requires :batch_no, type: String
|
989
|
+
requires :quantity, type: Integer
|
990
|
+
end
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
994
|
+
subject.get '/correctly_indexes' do
|
995
|
+
'correctly_indexes works!'
|
996
|
+
end
|
997
|
+
|
998
|
+
data = {
|
999
|
+
orders: [
|
1000
|
+
{ id: 70 },
|
1001
|
+
{ id: 77, drugs: [{ batch_no: 'A1234567', quantity: 12 }, { batch_no: 'B222222' }] }
|
1002
|
+
]
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
get '/correctly_indexes', data
|
1006
|
+
expect(last_response.body).to eq('orders[1][drugs][1][quantity] is missing')
|
1007
|
+
expect(last_response.status).to eq(400)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
context 'multiple levels of optional and requires settings' do
|
1011
|
+
before do
|
1012
|
+
subject.params do
|
1013
|
+
requires :top, type: Array do
|
1014
|
+
requires :top_id, type: Integer, allow_blank: false
|
1015
|
+
optional :middle_1, type: Array do
|
1016
|
+
requires :middle_1_id, type: Integer, allow_blank: false
|
1017
|
+
optional :middle_2, type: Array do
|
1018
|
+
requires :middle_2_id, type: String, allow_blank: false
|
1019
|
+
optional :bottom, type: Array do
|
1020
|
+
requires :bottom_id, type: Integer, allow_blank: false
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
subject.get '/multi_level' do
|
1028
|
+
'multi_level works!'
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
it 'with valid data' do
|
1033
|
+
data = {
|
1034
|
+
top: [
|
1035
|
+
{ top_id: 1, middle_1: [
|
1036
|
+
{ middle_1_id: 11 }, { middle_1_id: 12, middle_2: [
|
1037
|
+
{ middle_2_id: 121 }, { middle_2_id: 122, bottom: [{ bottom_id: 1221 }] }
|
1038
|
+
] }
|
1039
|
+
] },
|
1040
|
+
{ top_id: 2, middle_1: [
|
1041
|
+
{ middle_1_id: 21 }, { middle_1_id: 22, middle_2: [
|
1042
|
+
{ middle_2_id: 221 }
|
1043
|
+
] }
|
1044
|
+
] },
|
1045
|
+
{ top_id: 3, middle_1: [
|
1046
|
+
{ middle_1_id: 31 }, { middle_1_id: 32 }
|
1047
|
+
] },
|
1048
|
+
{ top_id: 4 }
|
1049
|
+
]
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
get '/multi_level', data
|
1053
|
+
expect(last_response.body).to eq('multi_level works!')
|
1054
|
+
expect(last_response.status).to eq(200)
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
it 'with invalid data' do
|
1058
|
+
data = {
|
1059
|
+
top: [
|
1060
|
+
{ top_id: 1, middle_1: [
|
1061
|
+
{ middle_1_id: 11 }, { middle_1_id: 12, middle_2: [
|
1062
|
+
{ middle_2_id: 121 }, { middle_2_id: 122, bottom: [{ bottom_id: nil }] }
|
1063
|
+
] }
|
1064
|
+
] },
|
1065
|
+
{ top_id: 2, middle_1: [
|
1066
|
+
{ middle_1_id: 21 }, { middle_1_id: 22, middle_2: [{ middle_2_id: nil }] }
|
1067
|
+
] },
|
1068
|
+
{ top_id: 3, middle_1: [
|
1069
|
+
{ middle_1_id: nil }, { middle_1_id: 32 }
|
1070
|
+
] },
|
1071
|
+
{ top_id: nil, missing_top_id: 4 }
|
1072
|
+
]
|
1073
|
+
}
|
1074
|
+
# debugger
|
1075
|
+
get '/multi_level', data
|
1076
|
+
expect(last_response.body.split(', ')).to match_array([
|
1077
|
+
'top[3][top_id] is empty',
|
1078
|
+
'top[2][middle_1][0][middle_1_id] is empty',
|
1079
|
+
'top[1][middle_1][1][middle_2][0][middle_2_id] is empty',
|
1080
|
+
'top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty'
|
1081
|
+
])
|
1082
|
+
expect(last_response.status).to eq(400)
|
1083
|
+
end
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
it 'exactly_one_of' do
|
1088
|
+
subject.params do
|
1089
|
+
requires :orders, type: Array do
|
1090
|
+
requires :id, type: Integer
|
1091
|
+
optional :drugs, type: Hash do
|
1092
|
+
optional :batch_no, type: String
|
1093
|
+
optional :batch_id, type: String
|
1094
|
+
exactly_one_of :batch_no, :batch_id
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
subject.get '/exactly_one_of' do
|
1100
|
+
'exactly_one_of works!'
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
data = {
|
1104
|
+
orders: [
|
1105
|
+
{ id: 77, drugs: { batch_no: 'A1234567' } },
|
1106
|
+
{ id: 70 }
|
1107
|
+
]
|
1108
|
+
}
|
1109
|
+
|
1110
|
+
get '/exactly_one_of', data
|
1111
|
+
expect(last_response.body).to eq('exactly_one_of works!')
|
1112
|
+
expect(last_response.status).to eq(200)
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
it 'at_least_one_of' do
|
1116
|
+
subject.params do
|
1117
|
+
requires :orders, type: Array do
|
1118
|
+
requires :id, type: Integer
|
1119
|
+
optional :drugs, type: Hash do
|
1120
|
+
optional :batch_no, type: String
|
1121
|
+
optional :batch_id, type: String
|
1122
|
+
at_least_one_of :batch_no, :batch_id
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
subject.get '/at_least_one_of' do
|
1128
|
+
'at_least_one_of works!'
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
data = {
|
1132
|
+
orders: [
|
1133
|
+
{ id: 77, drugs: { batch_no: 'A1234567' } },
|
1134
|
+
{ id: 70 }
|
1135
|
+
]
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
get '/at_least_one_of', data
|
1139
|
+
expect(last_response.body).to eq('at_least_one_of works!')
|
1140
|
+
expect(last_response.status).to eq(200)
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
it 'all_or_none_of' do
|
1144
|
+
subject.params do
|
1145
|
+
requires :orders, type: Array do
|
1146
|
+
requires :id, type: Integer
|
1147
|
+
optional :drugs, type: Hash do
|
1148
|
+
optional :batch_no, type: String
|
1149
|
+
optional :batch_id, type: String
|
1150
|
+
all_or_none_of :batch_no, :batch_id
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
subject.get '/all_or_none_of' do
|
1156
|
+
'all_or_none_of works!'
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
data = {
|
1160
|
+
orders: [
|
1161
|
+
{ id: 77, drugs: { batch_no: 'A1234567', batch_id: '12' } },
|
1162
|
+
{ id: 70 }
|
1163
|
+
]
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
get '/all_or_none_of', data
|
1167
|
+
expect(last_response.body).to eq('all_or_none_of works!')
|
1168
|
+
expect(last_response.status).to eq(200)
|
881
1169
|
end
|
882
1170
|
end
|
883
1171
|
|
@@ -901,15 +1189,24 @@ describe Grape::Validations do
|
|
901
1189
|
end
|
902
1190
|
|
903
1191
|
context 'custom validation' do
|
904
|
-
|
905
|
-
|
1192
|
+
let(:custom_validator) do
|
1193
|
+
Class.new(Grape::Validations::Validators::Base) do
|
906
1194
|
def validate_param!(attr_name, params)
|
907
1195
|
return if params[attr_name] == 'im custom'
|
1196
|
+
|
908
1197
|
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: 'is not custom!')
|
909
1198
|
end
|
910
1199
|
end
|
911
1200
|
end
|
912
1201
|
|
1202
|
+
before do
|
1203
|
+
described_class.register_validator('customvalidator', custom_validator)
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
after do
|
1207
|
+
described_class.deregister_validator('customvalidator')
|
1208
|
+
end
|
1209
|
+
|
913
1210
|
context 'when using optional with a custom validator' do
|
914
1211
|
before do
|
915
1212
|
subject.params do
|
@@ -1049,15 +1346,24 @@ describe Grape::Validations do
|
|
1049
1346
|
end
|
1050
1347
|
|
1051
1348
|
context 'when using options on param' do
|
1052
|
-
|
1053
|
-
|
1349
|
+
let(:custom_validator_with_options) do
|
1350
|
+
Class.new(Grape::Validations::Validators::Base) do
|
1054
1351
|
def validate_param!(attr_name, params)
|
1055
1352
|
return if params[attr_name] == @option[:text]
|
1353
|
+
|
1056
1354
|
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
|
1057
1355
|
end
|
1058
1356
|
end
|
1059
1357
|
end
|
1060
1358
|
|
1359
|
+
before do
|
1360
|
+
described_class.register_validator('customvalidator_with_options', custom_validator_with_options)
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
after do
|
1364
|
+
described_class.deregister_validator('customvalidator_with_options')
|
1365
|
+
end
|
1366
|
+
|
1061
1367
|
before do
|
1062
1368
|
subject.params do
|
1063
1369
|
optional :custom, customvalidator_with_options: { text: 'im custom with options', message: 'is not custom with options!' }
|
@@ -1122,14 +1428,14 @@ describe Grape::Validations do
|
|
1122
1428
|
subject.params do
|
1123
1429
|
use :pagination
|
1124
1430
|
end
|
1125
|
-
expect(
|
1431
|
+
expect(declared_params).to eq %i[page per_page]
|
1126
1432
|
end
|
1127
1433
|
|
1128
1434
|
it 'by #use with multiple params' do
|
1129
1435
|
subject.params do
|
1130
1436
|
use :pagination, :period
|
1131
1437
|
end
|
1132
|
-
expect(
|
1438
|
+
expect(declared_params).to eq %i[page per_page start_date end_date]
|
1133
1439
|
end
|
1134
1440
|
end
|
1135
1441
|
|
@@ -1152,21 +1458,25 @@ describe Grape::Validations do
|
|
1152
1458
|
}
|
1153
1459
|
end
|
1154
1460
|
end
|
1461
|
+
|
1155
1462
|
it 'returns defaults' do
|
1156
1463
|
get '/order'
|
1157
1464
|
expect(last_response.status).to eq(200)
|
1158
1465
|
expect(last_response.body).to eq({ order: :asc, order_by: :created_at }.to_json)
|
1159
1466
|
end
|
1467
|
+
|
1160
1468
|
it 'overrides default value for order' do
|
1161
1469
|
get '/order?order=desc'
|
1162
1470
|
expect(last_response.status).to eq(200)
|
1163
1471
|
expect(last_response.body).to eq({ order: :desc, order_by: :created_at }.to_json)
|
1164
1472
|
end
|
1473
|
+
|
1165
1474
|
it 'overrides default value for order_by' do
|
1166
1475
|
get '/order?order_by=name'
|
1167
1476
|
expect(last_response.status).to eq(200)
|
1168
1477
|
expect(last_response.body).to eq({ order: :asc, order_by: :name }.to_json)
|
1169
1478
|
end
|
1479
|
+
|
1170
1480
|
it 'fails with invalid value' do
|
1171
1481
|
get '/order?order=invalid'
|
1172
1482
|
expect(last_response.status).to eq(400)
|
@@ -1191,7 +1501,7 @@ describe Grape::Validations do
|
|
1191
1501
|
|
1192
1502
|
context 'all or none' do
|
1193
1503
|
context 'optional params' do
|
1194
|
-
before
|
1504
|
+
before do
|
1195
1505
|
subject.resource :custom_message do
|
1196
1506
|
params do
|
1197
1507
|
optional :beer
|
@@ -1204,17 +1514,20 @@ describe Grape::Validations do
|
|
1204
1514
|
end
|
1205
1515
|
end
|
1206
1516
|
end
|
1517
|
+
|
1207
1518
|
context 'with a custom validation message' do
|
1208
1519
|
it 'errors when any one is present' do
|
1209
1520
|
get '/custom_message/all_or_none', beer: 'string'
|
1210
1521
|
expect(last_response.status).to eq(400)
|
1211
1522
|
expect(last_response.body).to eq 'beer, wine, juice all params are required or none is required'
|
1212
1523
|
end
|
1524
|
+
|
1213
1525
|
it 'works when all params are present' do
|
1214
1526
|
get '/custom_message/all_or_none', beer: 'string', wine: 'anotherstring', juice: 'anotheranotherstring'
|
1215
1527
|
expect(last_response.status).to eq(200)
|
1216
1528
|
expect(last_response.body).to eq 'all_or_none works!'
|
1217
1529
|
end
|
1530
|
+
|
1218
1531
|
it 'works when none are present' do
|
1219
1532
|
get '/custom_message/all_or_none'
|
1220
1533
|
expect(last_response.status).to eq(200)
|
@@ -1378,7 +1691,7 @@ describe Grape::Validations do
|
|
1378
1691
|
|
1379
1692
|
context 'exactly one of' do
|
1380
1693
|
context 'params' do
|
1381
|
-
before
|
1694
|
+
before do
|
1382
1695
|
subject.resources :custom_message do
|
1383
1696
|
params do
|
1384
1697
|
optional :beer
|
@@ -1442,7 +1755,7 @@ describe Grape::Validations do
|
|
1442
1755
|
end
|
1443
1756
|
|
1444
1757
|
context 'nested params' do
|
1445
|
-
before
|
1758
|
+
before do
|
1446
1759
|
subject.params do
|
1447
1760
|
requires :nested, type: Hash do
|
1448
1761
|
optional :beer_nested
|
@@ -1484,7 +1797,7 @@ describe Grape::Validations do
|
|
1484
1797
|
|
1485
1798
|
context 'at least one of' do
|
1486
1799
|
context 'params' do
|
1487
|
-
before
|
1800
|
+
before do
|
1488
1801
|
subject.resources :custom_message do
|
1489
1802
|
params do
|
1490
1803
|
optional :beer
|
@@ -1548,7 +1861,7 @@ describe Grape::Validations do
|
|
1548
1861
|
end
|
1549
1862
|
|
1550
1863
|
context 'nested params' do
|
1551
|
-
before
|
1864
|
+
before do
|
1552
1865
|
subject.params do
|
1553
1866
|
requires :nested, type: Hash do
|
1554
1867
|
optional :beer
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
4
|
+
require 'grape'
|
5
|
+
|
6
|
+
describe Grape do
|
7
|
+
it 'eager_load!' do
|
8
|
+
require 'grape/eager_load'
|
9
|
+
expect { described_class.eager_load! }.not_to raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'compile!' do
|
13
|
+
expect { Class.new(Grape::API).compile! }.not_to raise_error
|
14
|
+
end
|
15
|
+
end
|