Skip to content

moeenn/vld

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VLD

A data validation library for GoLang.

Installation

Download the library

go get github.com/moeenn/vld

Why not go-playground/validator?

There is no denying that validator is an amazing package and is the ecosystem standard. However there are some issues with it

  • Struct tags are used to define field validators. Since tags are nothing more than strings, this method can be very error-prone.
  • The validation errors are structured non user-friedly way. This makes it difficult to format the validation errors in such a way that they can be displayed on the front-end clients properly.
  • The mechanism for defining custom validators is not intuitive.

vld attempts to solve these problems.

Basic usage

package main

import (
	"fmt"
	v "github.com/moeenn/vld"
)

type LoginForm struct {
	Email    string
	Password string
}

func main() {
	form := LoginForm{
		Email:    "admin-site.com",
		Password: "q1w2e3r4",
	}

	validations := []v.Validation{
		{
			Tag:   "email",
			Data:  form.Email,
			Rules: []v.Rule{v.NonEmptyString, v.Email},
		},
		{
			Tag:   "password",
			Data:  form.Password,
			Rules: []v.Rule{v.NonEmptyString, v.MinLength(8)},
		},
	}

	err := v.Validate(validations)
	if err != nil {
		validationErrors := err.(v.ValidationErrors)
		fmt.Printf("validation errors: %v\n", validationErrors.Errors)
		return
	}

	fmt.Println("validation successful")
}

Included validators

  • NonEmptyString: The input must be valid non-empty string value.
v.NonEmptyString
  • Length: The input string length must be exactly equal to the provided length.
// input string must be exactly 10 characters in length
v.Length(10)
  • MinLength: The input string length must be equal or more than the provided length.
// input string must be 5 characters or more in length
v.MinLength(5)
  • MaxLength: The input string length must be equal or less than the provided length.
// input string must be 5 characters or less in length
v.MaxLength(20)
  • MinFloat: The input floating-point number must be equal or more than the provided limit.
// input number must be at least 5.0 or more
v.MinFloat(5.0)
  • MaxFloat: The input floating-point number must be equal or less than the provided limit.
// input number must be 500.5 or less
v.MaxFloat(500.5)
  • MinInt: The input integer number must be equal or more than the provided limit.
// input number must be at least 100 or more
v.MinInt(100)
  • MaxInt: The input integer number must be equal or less than the provided limit.
// input number must be 200 or less
v.MaxInt(200)
  • LessThanFloat: The input floating-point number must be less than the provided limit.
// input number must be less than 20.0 (non-inclusive)
v.LessThanFloat(20.0)
  • GreaterThanFloat: The input floating-point number must be greater than the provided limit.
// input number must be greater than 10.5 (non-inclusive)
v.GreaterThanFloat(10.5)
  • LessThanInt: The input integer number must be less than the provided limit.
// input number must be less than 24 (non-inclusive)
v.LessThanInt(24)
  • GreaterThanInt: The input integer number must be greater than the provided limit.
// input number must be greater than 100 (non-inclusive)
v.GreaterThanInt(100)
  • Email: The input must be a valid email address.
v.Email
  • UUID: The input must be a valid UUID string
v.UUID
  • URL: The input must be a valid URL string
v.URL
  • Password: The input must be a strong password. The following rules are applied.
    • Minimum eight characters
    • At least one uppercase letter
    • At least one lowercase letter
    • At least one number
    • At least one special character
v.Password
  • JSON: Input must be a well-formed JSON string
v.JSON
  • ISODate: The input must be valid ISO timestamp according to RFC3339: Link.
// input string must conform to the format e.g 2024-03-22T12:35:05.115Z
v.ISODate
  • Date: The input must be a valid date-only string. Link.
// input must be in format e.g. 2023-10-05
v.Date
  • Time: The input must be a valid time-only string. Link.
// input must be in 24-hours format: e.g. 10:20:00
v.Time
  • Before date: TODO

  • Before or equal to date: TODO

  • After date: TODO

  • After or equal to date: TODO

  • StartsWith: The input string must begin with the provided prefix.

v.StartsWith("data:")
  • DoesntStartWith: The input string must not start with the provided prefix.
v.DoesntStartWith("mysql")
  • EndsWith: The input string must end with the provided suffix.
v.EndsWith("example")
  • DoesntEndWith: The input string must not end with the provided prefix.
v.DoesntEndWith("sample")
  • Enum: The input string must be equal to one of the provided valid values.
// values are provided in variadic fashion
v.Enum("Value One", "Value Two", "Value Three")
  • Regexp: The input value must satisfy the provided regular expression.
v.Regexp("^hello$")
  • Same: The input value must be the same as the required input. This validator can be used to confirm passwords.
import (
	"fmt"
	v "github.com/moeenn/vld"
)

type RegisterForm struct {
	Password        string
	ConfirmPassword string
}

func main() {
	form := RegisterForm{
		Password:        "A832KCN284506b@",
		ConfirmPassword: "A832KCN284506b@",
	}

	validations := []v.Validation{
		{
			Tag:   "password",
			Data:  form.Password,
			Rules: []v.Rule{v.NonEmptyString, v.Password},
		},
		{
			Tag:   "confirm_password",
			Data:  form.ConfirmPassword,
			Rules: []v.Rule{v.Same("Password", form.Password)},
		},
	}

	err := v.Validate(validations)
	if err != nil {
		validationErrors := err.(v.ValidationErrors)
		fmt.Printf("validation errors: %v\n", validationErrors.Errors)
		return
	}

	fmt.Println("validation successful")
}
  • Array: TODO

  • MinItems: TODO

  • MaxItems: TODO

Custom validators

In vld validators are plain functions. They can be defined as follows.

type ExampleForm struct {
	Slug string
}

func Slug(input any) error {
	err := errors.New("The input must be a valid slug")
	asString, ok := input.(string)
	if !ok {
		return err
	}

	if strings.Contains(asString, "_") {
		return err
	}
	return nil
}

func main() {
	form := ExampleForm{
		Slug: "some-slug-here",
	}

	validations := []v.Validation{
		{
			Tag:   "slug",
			Data:  form.Slug,
			Rules: []v.Rule{v.NonEmptyString, Slug}, // notice the user-defined validator
		},
	}

	err := v.Validate(validations)
	if err != nil {
		validationErrors := err.(v.ValidationErrors)
		fmt.Printf("validation errors: %v\n", validationErrors.Errors)
		return
	}
	
	// the input data is valid
    ...	
}

If the custom validator function required additional arguments, they can be defined as follows.

func StartsWith(prefix string) Rule {
	return func(input any) error {
		err := fmt.Errorf("The input must start with '%s'", prefix)
		asString, ok := input.(string)
		if !ok || !strings.HasPrefix(asString, prefix) {
			return err
		}
		return nil
	}
}

Releases

No releases published

Packages

No packages published

Languages