Checker is a lightweight Go library designed to validate user input efficiently. It supports validation of both struct fields and individual input values.
While there are numerous validation libraries available, Checker stands out due to its simplicity and lack of external dependencies. This makes it an ideal choice for developers who prefer to minimize dependencies and maintain control over their tools. Checker is straightforward to use and effectively meets your validation needs.
To begin using the Checker library, install it with the following command:
go get github.com/cinar/checker/v2
Then, import the library into your source file as shown below:
import (
checker "github.com/cinar/checker/v2"
)
Checker can validate user input stored in a struct by listing the checkers in the struct tags for each field. Here is an example:
type Person struct {
Name string `checkers:"trim required"`
}
person := &Person{
Name: " Onur Cinar ",
}
errors, valid := checker.CheckStruct(person)
if !valid {
// Handle validation errors
}
You can also validate individual user input by calling checker functions directly. Here is an example:
name := " Onur Cinar "
name, err := checker.Check(name, checker.Trim, checker.Required)
if err != nil {
// Handle validation error
}
The checkers and normalizers can also be provided through a config string. Here is an example:
name := " Onur Cinar "
name, err := checker.CheckWithConfig(name, "trim requied")
if err != nil {
// Handle validation error
}
For simpler validation, you can call individual checker functions. Here is an example:
name := "Onur Cinar"
err := checker.IsRequired(name)
if err != nil {
// Handle validation error
}
Checkers validate user input, while normalizers transform it into a preferred format. For example, a normalizer can trim spaces from a string or convert it to title case.
Although combining checkers and normalizers into a single library might seem unconventional, using them together can be beneficial. They can be mixed in any order when defining validation steps. For instance, you can use the trim
normalizer with the required
checker to first trim the input and then ensure it is provided. Here is an example:
type Person struct {
Name string `checkers:"trim required"`
}
ascii
: Ensures the string contains only ASCII characters.alphanumeric
: Ensures the string contains only letters and numbers.credit-card
: Ensures the string is a valid credit card number.cidr
: Ensures the string is a valid CIDR notation.digits
: Ensures the string contains only digits.email
: Ensures the string is a valid email address.fqdn
: Ensures the string is a valid fully qualified domain name.gte
: Ensures the value is greater than or equal to the specified number.hex
: Ensures the string contains only hexadecimal digits.ip
: Ensures the string is a valid IP address.ipv4
: Ensures the string is a valid IPv4 address.ipv6
: Ensures the string is a valid IPv6 address.isbn
: Ensures the string is a valid ISBN.lte
: Ensures the value is less than or equal to the specified number.luhn
: Ensures the string is a valid LUHN number.mac
: Ensures the string is a valid MAC address.max-len
: Ensures the length of the given value (string, slice, or map) is at most n.min-len
: Ensures the length of the given value (string, slice, or map) is at least n.required
Ensures the value is provided.regexp
Ensured the string matches the pattern.time
Ensured the string matches the provided time layout.url
: Ensures the string is a valid URL.
lower
: Converts the string to lowercase.title
: Converts the string to title case.trim-left
: Trims whitespace from the left side of the string.trim-right
: Trims whitespace from the right side of the string.trim
: Trims whitespace from both sides of the string.upper
: Converts the string to uppercase.html-escape
: Escapes special characters in the string for HTML.html-unescape
: Unescapes special characters in the string for HTML.url-escape
: Escapes special characters in the string for URLs.url-unescape
: Unescapes special characters in the string for URLs.
You can define custom checkers or normalizers and register them for use in your validation logic. Here is an example of how to create and register a custom checker:
checker.RegisterMaker("is-fruit", func(params string) v2.CheckFunc[reflect.Value] {
return func(value reflect.Value) (reflect.Value, error) {
stringValue := value.Interface().(string)
if stringValue == "apple" || stringValue == "banana" {
return value, nil
}
return value, v2.NewCheckError("NOT_FRUIT")
}
})
In this example, the custom checker is-fruit
checks if the input value is either "apple" or "banana". If the value is not one of these, it returns an error.
Once registered, you can use your custom checker in struct tags just like the built-in checkers:
type Item struct {
Name string `checkers:"is-fruit"`
}
item := &Item{
Name: "banana",
}
errors, valid := v2.CheckStruct(item)
if !valid {
fmt.Println(errors)
}
In this example, the is-fruit
checker is used to validate that the Name
field of the Item
struct is either "apple" or "banana".
When adding checker struct tags to a slice, you can use the @
prefix to indicate that the checker should be applied to the slice itself. Checkers without the @
prefix will be applied to the individual items within the slice. Here is an example:
type Person struct {
Name string `checkers:"required"`
Emails []string `checkers:"@max-len:2 max-len:64"`
}
In this example:
@max-len:2
ensures that theEmails
slice itself has at most two items.max-len:64
ensures that each email string within theEmails
slice has a maximum length of 64 characters.
When validation fails, Checker returns an error. By default, the Error() function provides a human-readable error message in en-US
locale.
_, err := checker.IsEmail("abcd")
if err != nil {
fmt.Println(err)
// Output: Not a valid email address.
}
To get error messages in other languages, use the ErrorWithLocale() function. By default, only en-US
is registered. You can register additional languages by calling RegisterLocale.
// Register de-DE localized error messages.
checker.RegisterLocale(locales.DeDE, locales.DeDEMessages)
_, err := checker.IsEmail("abcd")
if err != nil {
fmt.Println(err.ErrorWithLocale(locales.DeDE))
// Output: Keine gültige E-Mail-Adresse.
}
You can also customize existing error messages or add new ones to locales.EnUSMessages
and other locale maps.
// Register the en-US localized error message for the custom NOT_FRUIT error code.
locales.EnUSMessages["NOT_FRUIT"] = "Not a fruit name."
errors, valid := v2.CheckStruct(item)
if !valid {
fmt.Println(errors)
// Output: map[Name:Not a fruit name.]
}
Error messages are generated using Golang template functions, allowing them to include variables.
// Custrom checker error containing the item name.
err := checker.NewCheckErrorWithData(
"NOT_FRUIT",
map[string]interface{}{
"name": "abcd",
},
)
// Register the en-US localized error message for the custom NOT_FRUIT error code.
locales.EnUSMessages["NOT_FRUIT"] = "Name {{ .name }} is not a fruit name."
errors, valid := v2.CheckStruct(item)
if !valid {
fmt.Println(errors)
// Output: map[Name:Name abcd is not a fruit name.]
}
Anyone can contribute to Checkers library. Please make sure to read our Contributor Covenant Code of Conduct guide first. Follow the How to Contribute to Checker to contribute.
This library is free to use, modify, and distribute under the terms of the MIT license. The full license text can be found in the LICENSE file.
The MIT license is a permissive license that allows you to do almost anything with the library, as long as you retain the copyright notice and the license text. This means that you can use the library in commercial products, modify it, and redistribute it without having to ask for permission from the authors.
The LICENSE file is located in the root directory of the library. You can open it in a text editor to read the full license text.