grape 1.3.3 → 1.6.2
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.
- 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
|