From 581d2698d5b4a22da740b23e0ed6b0712a4d8622 Mon Sep 17 00:00:00 2001 From: Pantelis Sampaziotis Date: Tue, 4 Feb 2020 18:04:58 +0200 Subject: [PATCH] Added isJSON validation --- baked_in.go | 14 +++++++++++ doc.go | 6 +++++ translations/en/en.go | 5 ++++ translations/en/en_test.go | 5 ++++ validator_test.go | 48 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/baked_in.go b/baked_in.go index 9eff0e4..aad4738 100644 --- a/baked_in.go +++ b/baked_in.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/json" "fmt" "net" "net/url" @@ -166,6 +167,7 @@ var ( "html_encoded": isHTMLEncoded, "url_encoded": isURLEncoded, "dir": isDir, + "json": isJSON, } ) @@ -2007,3 +2009,15 @@ func isDir(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } + +// isJSON is the validation function for validating if the current field's value is a valid json string. +func isJSON(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + val := field.String() + return json.Valid([]byte(val)) + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} diff --git a/doc.go b/doc.go index 799882c..100163d 100644 --- a/doc.go +++ b/doc.go @@ -673,6 +673,12 @@ does any email provider accept all possibilities. Usage: email +JSON String + +This validates that a string value is valid JSON + + Usage: json + File path This validates that a string value contains a valid file path and that diff --git a/translations/en/en.go b/translations/en/en.go index 3b1058b..db48401 100644 --- a/translations/en/en.go +++ b/translations/en/en.go @@ -1321,6 +1321,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er return s }, }, + { + tag: "json", + translation: "{0} must be a valid json string", + override: false, + }, } for _, t := range translations { diff --git a/translations/en/en_test.go b/translations/en/en_test.go index cddcb84..d1fd62c 100644 --- a/translations/en/en_test.go +++ b/translations/en/en_test.go @@ -141,6 +141,7 @@ func TestTranslations(t *testing.T) { UniqueSlice []string `validate:"unique"` UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` + JSONString string `validate:"json"` } var test Test @@ -632,6 +633,10 @@ func TestTranslations(t *testing.T) { ns: "Test.UniqueMap", expected: "UniqueMap must contain unique values", }, + { + ns: "Test.JSONString", + expected: "JSONString must be a valid json string", + }, } for _, tt := range tests { diff --git a/validator_test.go b/validator_test.go index 2c8b96b..b6ebedb 100644 --- a/validator_test.go +++ b/validator_test.go @@ -9003,3 +9003,51 @@ func TestGetTag(t *testing.T) { Equal(t, errs, nil) Equal(t, tag, "mytag") } + +func TestJSONValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {`foo`, false}, + {`}{`, false}, + {`{]`, false}, + {`{}`, true}, + {`{"foo":"bar"}`, true}, + {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, + {`{"foo": 3 "bar": 4}`, false}, + {`{"foo": 3 ,"bar": 4`, false}, + {`{foo": 3, "bar": 4}`, false}, + {`foo`, false}, + {`1`, true}, + {`true`, true}, + {`null`, true}, + {`"null"`, true}, + } + + validate := New() + + for i, test := range tests { + + errs := validate.Var(test.param, "json") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d json failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d json failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "json" { + t.Fatalf("Index: %d json failed Error: %s", i, errs) + } + } + } + } + + PanicMatches(t, func() { + _ = validate.Var(2, "json") + }, "Bad field type int") +}