GitHub - tiendc/go-validator: Intuitive validation library for Golang (original) (raw)

Go Version GoDoc Build Status Coverage Status GoReport

Fast and intuitive validation library for Go

This lib uses the Is... validation functions from the govalidator project.

Installation

go get github.com/tiendc/go-validator

Usage

General usage

import (
    vld "github.com/tiendc/go-validator"
)

type Person struct {
    FirstName string
    LastName  string
    Birthdate time.Time

    Unemployed bool
    Salary     uint
    Rank       string
    WorkEmail  string
    Projects   []string
    TaskMap    map[string]Task
}
var p Person

errs := vld.Validate(
    // Validate first and last names separately
    vld.StrLen(&p.FirstName, 3, 30).OnError(
        vld.SetField("first_name", nil),
        vld.SetCustomKey("ERR_VLD_PERSON_FIRST_NAME_INVALID"),
    ),
    vld.StrLen(&p.FirstName, 3, 30).OnError(
        vld.SetField("last_name", nil),
        vld.SetCustomKey("ERR_VLD_PERSON_LAST_NAME_INVALID"),
    ),

    // OR use this to produce only one error when one of them fails
    vld.Group(
        vld.StrLen(&p.FirstName, 3, 30),
        vld.StrLen(&p.LastName, 3, 30),
    ).OnError(
        vld.SetField("name", nil),
        vld.SetCustomKey("ERR_VLD_PERSON_NAME_INVALID"),
    ),

    // Birthdate is optional, but when it's present, it must be within 1950 and now
    vld.When(!p.Birthdate.IsZero()).Then(
        vld.TimeRange(p.Birthdate, <1950-01-01>, time.Now()).OnError(...),
    )

    vld.When(!p.Unemployed).Then(
        vld.Required(&p.Salary),
        // Work email must be valid
        vld.StrIsEmail(&p.WorkEmail),

        // Rank must be one of the constants
        vld.StrIn(&p.Rank, "Employee", "Manager", "Director"),
        vld.Case(
            vld.When(p.Rank == "Manager").Then(vld.NumGT(&p.Salary, 10000)),
            vld.When(p.Rank == "Director").Then(vld.NumGT(&p.Salary, 30000)),
        ).Default(
            vld.NumLT(&p.Salary, 10000),
        ),

        // Projects are optional, but when they are present, they must be unique and sorted
        vld.When(len(p.Projects) > 0).Then(
            vld.SliceUnique(p.Projects).OnError(...),
            vld.SliceSorted(p.Projects).OnError(...),
        )
    ).Else(
        // When person is unemployed
        vld.NumEQ(&p.Salary, 0),
        vld.StrEQ(&p.WorkEmail, ""),
    ),

    // Validate slice elements
    vld.Slice(p.Projects).ForEach(func(elem int, index int, validator ItemValidator) {
        validator.Validate(
            vld.StrLen(&elem, 10, 30).OnError(
                vld.SetField(fmt.Sprintf("projects[%d]", index), nil),
                vld.SetCustomKey("ERR_VLD_PROJECT_NAME_INVALID"),
            ),
        )
    }),

    // Validate map entries
    vld.Map(p.TaskMap).ForEach(func(k string, v Task, validator ItemValidator) {
        validator.Validate(
            vld.StrLen(&v.Name, 10, 30).OnError(
                vld.SetField(fmt.Sprintf("taskMap[%s].name", k), nil),
                vld.SetCustomKey("ERR_VLD_TASK_NAME_INVALID"),
            ),
        )
    }),

    // OTHER FUNCTIONS
    // Pass if at least one of the validations passes
    vld.OneOf(
        // List of validations
    ),

    // Pass if exact one of the validations passes
    vld.ExactOneOf(
        // List of validations
    ),

    // Pass if none of the validations passes
    vld.NotOf(
        // List of validations
    ),
)

for _, e := range errs {
    detail, warnErr := e.BuildDetail()
    fmt.Printf("%+v\n", detail)
}

Error message localization

Custom error param formatter

errs := Validate(
    NumLT(&budget, 1000000).OnError(
        SetField("Budget", nil),
    ),
)

// e.BuildDetail() may produce message `Budget must be less than 1000000`,
// but you may want a message like: `Budget must be less than 1,000,000`.
// Let's use a custom formatter

errs := Validate(
    NumLT(&budget, 1000000).OnError(
        SetField("Budget", nil),
        SetNumParamFormatter(NewDecimalFormatFunc('.', ',', "%f")),
    ),
)

Contributing

License