Validate Golang request data with simple rules. Highly inspired by Laravel's request validation.

Overview

govalidator

Build Status Project status Go Report Card Coverage Status GoDoc License

Validate golang request data with simple rules. Highly inspired by Laravel's request validation.

Installation

Install the package using

$ go get github.com/thedevsaddam/govalidator
// or
$ go get gopkg.in/thedevsaddam/govalidator.v1

Usage

To use the package import it in your *.go code

import "github.com/thedevsaddam/govalidator"
// or
import "gopkg.in/thedevsaddam/govalidator.v1"

Example

Validate form-data, x-www-form-urlencoded and query params

package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/thedevsaddam/govalidator"
)

func handler(w http.ResponseWriter, r *http.Request) {
	rules := govalidator.MapData{
		"username": []string{"required", "between:3,8"},
		"email":    []string{"required", "min:4", "max:20", "email"},
		"web":      []string{"url"},
		"phone":    []string{"digits:11"},
		"agree":    []string{"bool"},
		"dob":      []string{"date"},
	}

	messages := govalidator.MapData{
		"username": []string{"required:আপনাকে অবশ্যই ইউজারনেম দিতে হবে", "between:ইউজারনেম অবশ্যই ৩-৮ অক্ষর হতে হবে"},
		"phone":    []string{"digits:ফোন নাম্বার অবশ্যই ১১ নম্বারের হতে হবে"},
	}

	opts := govalidator.Options{
		Request:         r,        // request object
		Rules:           rules,    // rules map
		Messages:        messages, // custom message map (Optional)
		RequiredDefault: true,     // all the field to be pass the rules
	}
	v := govalidator.New(opts)
	e := v.Validate()
	err := map[string]interface{}{"validationError": e}
	w.Header().Set("Content-type", "application/json")
	json.NewEncoder(w).Encode(err)
}

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("Listening on port: 9000")
	http.ListenAndServe(":9000", nil)
}

Send request to the server using curl or postman: curl GET "http://localhost:9000?web=&phone=&zip=&dob=&agree="

Response

{
    "validationError": {
        "agree": [
            "The agree may only contain boolean value, string or int 0, 1"
        ],
        "dob": [
            "The dob field must be a valid date format. e.g: yyyy-mm-dd, yyyy/mm/dd etc"
        ],
        "email": [
            "The email field is required",
            "The email field must be a valid email address"
        ],
        "phone": [
            "ফোন নাম্বার অবশ্যই ১১ নম্বারের হতে হবে"
        ],
        "username": [
            "আপনাকে অবশ্যই ইউজারনেম দিতে হবে",
            "ইউজারনেম অবশ্যই ৩-৮ অক্ষর হতে হবে"
        ],
        "web": [
            "The web field format is invalid"
        ]
    }
}

More examples

Validate file

Validate application/json or text/plain as raw body

Validate struct directly

Validation Rules

  • alpha The field under validation must be entirely alphabetic characters.
  • alpha_dash The field under validation may have alpha-numeric characters, as well as dashes and underscores.
  • alpha_space The field under validation may have alpha-numeric characters, as well as dashes, underscores and space.
  • alpha_num The field under validation must be entirely alpha-numeric characters.
  • between:numeric,numeric The field under validation check the length of characters/ length of array, slice, map/ range between two integer or float number etc.
  • numeric The field under validation must be entirely numeric characters.
  • numeric_between:numeric,numeric The field under validation must be a numeric value between the range. e.g: numeric_between:18,65 may contains numeric value like 35, 55 . You can also pass float value to check. Moreover, both bounds can be omitted to create an unbounded minimum (e.g: numeric_between:,65) or an unbounded maximum (e.g: numeric_between:-1,).
  • bool The field under validation must be able to be cast as a boolean. Accepted input are true, false, 1, 0, "1" and "0".
  • credit_card The field under validation must have a valid credit card number. Accepted cards are Visa, MasterCard, American Express, Diners Club, Discover and JCB card
  • coordinate The field under validation must have a value of valid coordinate.
  • css_color The field under validation must have a value of valid CSS color. Accepted colors are hex, rgb, rgba, hsl, hsla like #909, #00aaff, rgb(255,122,122)
  • date The field under validation must have a valid date of format yyyy-mm-dd or yyyy/mm/dd.
  • date:dd-mm-yyyy The field under validation must have a valid date of format dd-mm-yyyy.
  • digits:int The field under validation must be numeric and must have an exact length of value.
  • digits_between:int,int The field under validation must be numeric and must have length between the range. e.g: digits_between:3,5 may contains digits like 2323, 12435
  • in:foo,bar The field under validation must have one of the values. e.g: in:admin,manager,user must contain the values (admin or manager or user)
  • not_in:foo,bar The field under validation must have one value except foo,bar. e.g: not_in:admin,manager,user must not contain the values (admin or manager or user)
  • email The field under validation must have a valid email.
  • float The field under validation must have a valid float number.
  • mac_address The field under validation must have be a valid Mac Address.
  • min:numeric The field under validation must have a min length of characters for string, items length for slice/map, value for integer or float. e.g: min:3 may contains characters minimum length of 3 like "john", "jane", "jane321" but not "mr", "xy"
  • max:numeric The field under validation must have a max length of characters for string, items length for slice/map, value for integer or float. e.g: max:6 may contains characters maximum length of 6 like "john doe", "jane doe" but not "john", "jane"
  • len:numeric The field under validation must have an exact length of characters, exact integer or float value, exact size of map/slice. e.g: len:4 may contains characters exact length of 4 like Food, Mood, Good
  • ip The field under validation must be a valid IP address.
  • ip_v4 The field under validation must be a valid IP V4 address.
  • ip_v6 The field under validation must be a valid IP V6 address.
  • json The field under validation must be a valid JSON string.
  • lat The field under validation must be a valid latitude.
  • lon The field under validation must be a valid longitude.
  • regex:regular expression The field under validation validate against the regex. e.g: regex:^[a-zA-Z]+$ validate the letters.
  • required The field under validation must be present in the input data and not empty. A field is considered "empty" if one of the following conditions are true: 1) The value is null. 2)The value is an empty string. 3) Zero length of map, slice. 4) Zero value for integer or float
  • size:integer The field under validation validate a file size only in form-data (see example)
  • ext:jpg,png The field under validation validate a file extension (see example)
  • mime:image/jpg,image/png The field under validation validate a file mime type (see example)
  • url The field under validation must be a valid URL.
  • uuid The field under validation must be a valid UUID.
  • uuid_v3 The field under validation must be a valid UUID V3.
  • uuid_v4 The field under validation must be a valid UUID V4.
  • uuid_v5 The field under validation must be a valid UUID V5.

Add Custom Rules

func init() {
	// simple example
	govalidator.AddCustomRule("must_john", func(field string, rule string, message string, value interface{}) error {
		val := value.(string)
		if val != "john" || val != "John" {
			return fmt.Errorf("The %s field must be John or john", field)
		}
		return nil
	})

	// custom rules to take fixed length word.
	// e.g: word:5 will throw error if the field does not contain exact 5 word
	govalidator.AddCustomRule("word", func(field string, rule string, message string, value interface{}) error {
		valSlice := strings.Fields(value.(string))
		l, _ := strconv.Atoi(strings.TrimPrefix(rule, "word:")) //handle other error
		if len(valSlice) != l {
			return fmt.Errorf("The %s field must be %d word", field, l)
		}
		return nil
	})

}

Note: Array, map, slice can be validated by adding custom rules.

Custom Message/ Localization

If you need to translate validation message you can pass messages as options.

messages := govalidator.MapData{
	"username": []string{"required:You must provide username", "between:The username field must be between 3 to 8 chars"},
	"zip":      []string{"numeric:Please provide zip field as numeric"},
}

opts := govalidator.Options{
	Messages:        messages,
}

Contribution

If you are interested to make the package better please send pull requests or create an issue so that others can fix. Read the contribution guide here

Contributors

See all contributors

See benchmarks

Read API documentation

License

The govalidator is an open-source software licensed under the MIT License.

Comments
  • Fixed support of negative numbers in `numeric` rule

    Fixed support of negative numbers in `numeric` rule

    The numeric rule was not handling negative numbers correctly as the Numeric regexp was not accepting negative numbers which is valid.

    Fixed that and added a bunch of test cases around negative numbers for numeric, numeric_between, min and max.

    opened by maoueh 11
  • File Validation error

    File Validation error

    Using your example

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"net/http"
    	"github.com/thedevsaddam/govalidator"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	rules := govalidator.MapData{
    		"stock_image": []string{"ext:jpg,jpeg,png,bmp", "size:20000000", "required"},
    	}
    
    	opts := govalidator.Options{
    		Request: r,     // request object
    		Rules:   rules, // rules map
    	}
    	v := govalidator.New(opts)
    	e := v.Validate()
    	err := map[string]interface{}{"validationError": e}
    	fmt.Fprintln(w, err)
    
    }
    
    func main() {
    	http.HandleFunc("/", handler)
    	fmt.Println("Listening on port: 9000")
    	http.ListenAndServe(":9000", nil)
    }
    

    always yield me to map[validationError:map[stock_image:[The stock_image field is required]]] even though i already select a file to be upload.

    I think the problem is in validator.go line 87 (v.Opts.Request.Form.Get) , since its files, its not available in v.Opts.Request.Form instead available in v.Opts.RequestMultiPartForm

    Thats why validateCustomRules(field, rule, msg, reqVal, errsBag) always return an error, since reqVal always empty

    bug 
    opened by nmsobri 10
  • email required when no required rule is set

    email required when no required rule is set

    these rules

    
    	rules := govalidator.MapData{
    		"mail1":   []string{"required", "email"},
    		"mail2":      []string{"email"},
    	}
    

    give me mail2 The sender field must be a valid email address

    I think that the correct behavior should be that the validation allows empty emails

    opened by g13013 7
  • File validation not working?

    File validation not working?

    Hey adam..

    I think the form validation is not working when the rules is optional (no required)

    func handler(w http.ResponseWriter, r *http.Request) {
    	rules := govalidator.MapData{
                    //Notice this rules is optional
    		"file:photo": []string{"ext:jpg,png", "size:2000000", "mime:jpg,png"},
    	}
    
    	messages := govalidator.MapData{
    		"file:photo": []string{"ext:Only jpg/png is allowed", "size:Maximux size is 2Mb"},
    	}
    
    	opts := govalidator.Options{
    		Request: r,     // request object
    		Rules:   rules, // rules map,
    		Messages: messages,
    	}
    
    	v := govalidator.New(opts)
    	e := v.Validate()
    	err := map[string]interface{}{"validationError": e}
    	w.Header().Set("Content-type", "applciation/json")
    	json.NewEncoder(w).Encode(err)
    }
    
    

    Eventhough im not uploading any file, the validation still run through yielding me to Only jpg/png is allowed

    Regarding this line: https://github.com/thedevsaddam/govalidator/blob/master/validator.go#L95

    Even though there is no uploaded file, file is still not nil I think the correct way should be

    if strings.HasPrefix(field, "file:") {
    	fld := strings.TrimPrefix(field, "file:")
    	file, fileHeader, _ := v.Opts.Request.FormFile(fld)
    	if fileHeader.Filename  != "" {
    		validateFiles(v.Opts.Request, fld, rule, msg, errsBag)
    		validateCustomRules(fld, rule, msg, file, errsBag)
    	} else {
    		validateCustomRules(fld, rule, msg, nil, errsBag)
    	}
    }
    

    Some additional info: Golang v1.10 I'm entirely not sure prior to v1.10 whether its working or not

    opened by nmsobri 6
  • Enhancement `numeric_between` to accept unbounded min/max

    Enhancement `numeric_between` to accept unbounded min/max

    The numeric_between is now able to be configured without a min value (numeric_between:,10) creating a validator that will accept any values lower or equal to 10 and without a max value (numeric_between:10,) creating a validator that will accept any values higher or equal to 10.

    opened by maoueh 5
  • validator throws a

    validator throws a "required field" error even if the data is present in the payload

    Hi, I have recently started using the govalidator library and I must say this has solved a lot of problems for me.

    I am trying to validate the following request but I am getting an error. Could you please let me know if it's a bug or am I doing something wrong?

    payload: {"user":"uewbf937rweab", "data": {"event": "cm", "messages": "["Hello to the world!"]"}}

    rules: govalidator.MapData{ "user": []string{"required"}, "data": []string{"required"}, }

    error: "the data field is required"

    enhancement 
    opened by rahulxxarora 5
  • Remove rules deletion on validation

    Remove rules deletion on validation

    Hi, @thedevsaddam .

    It seems that fields of Options.Rule are deleted in some case, so Options.Rule cannot be used more than once. This behavior seems a bit inconvenient, so I'd like to fix it. What do you think?

    opened by bluele 4
  • How about set default value for field in struct?

    How about set default value for field in struct?

    How about setting default value by providing default struct tag to set default value when the field was null in validation phrase. As below Username and Email fields

    type user struct {
    	Username string           `json:"username",default:"foo"`
    	Email    string           `json:"email",default:"[email protected]"`
    	Web      string           `json:"web"`
    	Age      govalidator.Int  `json:"age"`
    	Agree    govalidator.Bool `json:"agree"`
    }
    
    rules := govalidator.MapData{
    	"username": []string{"required", "between:3,8"},
    	"email":    []string{"required", "min:4", "max:20", "email"},
    	"web":      []string{"url"},
    	"phone":    []string{"digits:11"}
    	"agree":    []string{"bool"},
    	"dob":      []string{"date"},
    }
    
    opts := govalidator.Options{
    	Request:         &user{Username: "test",  ....},        // use struct instead net.http
    	Rules:           rules,    // rules map
    	Messages:        messages, // custom message map (Optional)
    	RequiredDefault: true,     // all the field to be pass the rules
    } 
    
    question 
    opened by jkryanchou 4
  • Struct validation

    Struct validation

    I want to check validation struct instead *net.http. I can't find any sample code. for example :

    type user struct {
    	Username string           `json:"username"`
    	Email    string           `json:"email"`
    	Web      string           `json:"web"`
    	Age      govalidator.Int  `json:"age"`
    	Agree    govalidator.Bool `json:"agree"`
    }
    
    rules := govalidator.MapData{
    	"username": []string{"required", "between:3,8"},
    	"email":    []string{"required", "min:4", "max:20", "email"},
    	"web":      []string{"url"},
    	"phone":    []string{"digits:11"}
    	"agree":    []string{"bool"},
    	"dob":      []string{"date"},
    }
    
    opts := govalidator.Options{
    	Request:         &user{Username: "test",  ....},        // use struct instead net.http
    	Rules:           rules,    // rules map
    	Messages:        messages, // custom message map (Optional)
    	RequiredDefault: true,     // all the field to be pass the rules
    } 
    

    how I can do this ?

    enhancement 
    opened by amirkheirabadi73 4
  • digits:int goes scientific at 13 digits

    digits:int goes scientific at 13 digits

    rule digits:12, no problem. rule digits:13 ends up taking a 13 digit integer and formatting to scientific notation, resulting in a string length of 15. Example:

    rules := govalidator.MapData{ "createdEpochMs": []string{"required", "digits:13"} }
    

    when passing 1541689038000 to rules:go:toString(value), a string value of 1.541689038e+12 is returned. utils:go:toString(value) formats interface{} to "%#v" which exceeds the default width.

    Considering you know the intended length "l" based on the "digits:" suffix and that it's an integer type, one possible approach to resolve this might be to use an explicit width format on an alternate "toString" method:

    func toNumericString(v interface{}, width int, precision int) string {
    	str, ok := v.(string)
    	if !ok {
    		format := fmt.Sprintf("%%%d.%df", width, precision)
    		str = fmt.Sprintf(format, v)
    	}
    	return str
    }
    

    This is what the call would look like:

    str := toNumericString(value, l, 0)
    if len(str) != l || !isNumeric(str) {
    	return err
    }
    

    There may be even simpler ways to do it. Just looking to validate an epoch in milliseconds. I will likely fall back on regex validation for the time-being.

    bug enhancement 
    opened by setheen 3
  • Fixed tree typo's in the docs

    Fixed tree typo's in the docs

    Just a small thing so hope you don't mind I'm opening a special pull request for it. But I noticed it right away when reading your docs.

    Kind regards.

    opened by mkromkamp 3
  • how to validate struct in struct?

    how to validate struct in struct?

    code like this

    // QueryPageProjectGrailRequest Request 请求 type QueryPageProjectGrailRequest struct { PageNo int32 json:"page_no" // 页码 PageSize int32 json:"page_size" // 每页数量 Sort string json:"sort" // 排序,支持多个 such as "col1 desc, col2 asc" Filter []queryProjectGrailFilter json:"filter" // 筛选(高级查询) Keywords []string json:"keywords" // 全文检索能力 }

    type queryProjectGrailFilter struct { Field string json:"field" Condition string json:"condition" Relation string json:"relation" Value string json:"value" }

    I don't know how to validator field in filter? such as filter.relation

    // relation didn't work rules := govalidator.MapData{ "page_no": []string{"required", "numeric_between:1,100000"}, "page_size": []string{"required", "numeric_between:1,1000"}, "relation": []string{"between:1,5"}, }

    opened by YellowWinterSun 0
  • How to validate  slice of struct ?

    How to validate slice of struct ?

      type User struct {
    	  FirstName string
    	  LastName string
    	  Address AddressSliceWrapper
      }
      
      type Address struct {
    	  IsMailing bool 
      }
      
      type Addresses []Address
    

    // AddressSliceWrapper embeds the alias type for the sake of embedding a slice. // This is very heavy-handed.

    type AddressSliceWrapper struct {
    	Addresses
    }
    
    opened by mdsohelmia 0
  • Is there any way to check if a custom rule already exists or not?

    Is there any way to check if a custom rule already exists or not?

    Hey Saddam,

    Great package 👍

    I know that if I have a specific requirement for a rule I can use the AddCustomRule() method. However, it's hard to use it within a request-bound situation. For instance, consider a "password confirmation" situation like this:

    // Somewhere in your handler
    
    type RegisterRequest struct {
    	FirstName            string `json:"firstName"`
    	LastName             string `json:"lastName"`
    	Email                string `json:"email"`
    	Password             string `json:"password"`
    	PasswordConfirmation string `json:"passwordConfirmation"`
    }
    
    var registerRequest RegisterRequest
    
    rules := govalidator.MapData{
    	"firstName": []string{"required", "max:64"},
    	"lastName":  []string{"required", "max:64"},
    	"email":     []string{"required", "email"},
    	"password":  []string{"required", "confirmed"},
    }
    
    opts := govalidator.Options{
    	Request: r,     // request object
    	Rules:   rules, // rules map
    	Data:    &registerRequest,
    	RequiredDefault: true, // all the field to be pass the rules
    }
    
    govalidator.AddCustomRule("confirmed", func(field string, rule string, message string, value interface{}) error {
    	val := value.(string)
    	if val != registerRequest.PasswordConfirmation {
    		return fmt.Errorf("The %s confirmation does not match", field)
    	}
    	return nil
    })
    

    This would only work on the first request, any subsequent request will fail because of this: https://github.com/thedevsaddam/govalidator/blob/410bf76327c31ef88a2cc858060b4016dcb80bb3/rules.go#L21-L24

    You could say I could define the rule outside the handler, but as you can see the rule has a dependency on another field of the request body.

    Is there any way I can get around this?

    Off the top of my head, here are some of the things I thought about that would not cause a breaking change:

    • We could export the isRuleExist function, making it public (IsRuleExist) from private:

      https://github.com/thedevsaddam/govalidator/blob/master/utils.go#L20

    • Or, we could add a new method like AddCustomRuleOnce() which will internally check if the rule exists in the rulesFuncMap and if it does, skip adding the rule.

    • Or, we could introduce a new method called RemoveCustomRule() which will remove an existing rule from the rulesFuncMap and the same rule can be added each time without panicing, even if the rule is request-bound. Because on every request, the rule is being added and destroyed.

    opened by tanmaymishu 1
  • added ConvertFastHttpRequest function that will help to convert fasthttp and gofiber context to net/http request

    added ConvertFastHttpRequest function that will help to convert fasthttp and gofiber context to net/http request

    this function will help you to convert fasthttp and gofiber context to a http/net request so that fasthttp and gofiber users can also utilize this package

    opened by umerbilal-tech 2
Releases(v1.9.9)
Owner
Saddam H
Sr. Software Engineer @ Pathao Inc | Open Source Enthusiast | Love to write elegant code | Golang | Distributed Systems
Saddam H
Golang parameter validation, which can replace go-playground/validator, includes ncluding Cross Field, Map, Slice and Array diving, provides readable,flexible, configurable validation.

Checker 中文版本 Checker is a parameter validation package, can be use in struct/non-struct validation, including cross field validation in struct, elemen

Liang Yaopei 79 Dec 16, 2022
Gookit 824 Dec 28, 2022
Simple module for validation inn control number

simple module for validation inn control number

Pavel 1 Sep 4, 2022
This is a tool to validate the Pull Secret file from the command line interface.

pullsecret-validator-cli Description This is a tool to validate the Pull Secret file from the command line interface. This repository and its contents

Red Hat Systems Engineering Team 4 May 10, 2022
This project is a Library to validate a pull secret

lib-ps-validator Description This repository and its contents are completely UNSUPPORTED in any way and are not part of official documentation. Lib to

Red Hat Systems Engineering Team 3 Jul 21, 2021
A demo project shows how to use validator to validate parameters

validator-demo This project is a demo project shows how to use validator to validate parameters use case install requirements go get github.com/favadi

ziyi.wang 1 Jan 10, 2022
Validate the Strength of a Password in Go

go-password-validator Simple password validator using raw entropy values. Hit the project with a star if you find it useful ⭐ Supported by Qvault This

Lane Wagner 371 Dec 31, 2022
🥬 validate. simply.

?? validate. simply. no reflection. no gencode. hierarchical and extendable. fast. ~100LOC. generics. This is convenient when you have custom validati

Nikolay Dubina 17 Oct 3, 2022
Struct validation using tags

Govalid Use Govalid to validate structs. Documentation For full documentation see pkg.go.dev. Example package main import ( "fmt" "log" "strings"

Travis Harmon 32 Dec 6, 2022
:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving

Package validator Package validator implements value validations for structs and individual fields based on tags. It has the following unique features

Go Playgound 12.2k Jan 1, 2023
An interesting go struct tag expression syntax for field validation, etc.

go-tagexpr An interesting go struct tag expression syntax for field validation, etc. Usage Validator: A powerful validator that supports struct tag ex

Bytedance Inc. 1.3k Jan 9, 2023
Swagger builder and input validation for Go servers

crud A Swagger/OpenAPI builder and validation library for building HTTP/REST APIs. Heavily inspired by hapi and the hapi-swagger projects. No addition

Jake Coffman 38 Jan 5, 2023
Go package containing implementations of efficient encoding, decoding, and validation APIs.

encoding Go package containing implementations of encoders and decoders for various data formats. Motivation At Segment, we do a lot of marshaling and

Segment 883 Dec 25, 2022
Library providing opanapi3 and Go types for store/validation and transfer of ISO-4217, ISO-3166, and other types.

go-types This library has been created with the purpose to facilitate the store, validation, and transfer of Go ISO-3166/ISO-4217/timezones/emails/URL

Mikalai Konan 15 Nov 9, 2022
Opinionated go to validation library

?? valeed Your opinionated go-to validation library. Struct tag-based. Validate here, validate there, validate everywhere. Sleek and simple validation

Avré Barra 0 Jul 21, 2022
Gin Middleware to extract json tag value from playground validator's errors validation

Json Tag Extractor for Go-Playground Validator This is Gin Middleware that aim to extract json tag and than store it to FieldError.Field() object. Ins

Muhamad Surya Iksanudin 0 Jan 14, 2022
Validator - Replace the validation framework used by gin

validator Replace the validation framework used by gin replace mod:replace githu

null 2 Jan 18, 2022
golang request validator

validator Golang 参数验证器,目前只支持POST请求,JSON格式参数验证 亮点 1、验证时只要有一个错误,错误信息立即返回 2、可自定义参数别名显示错误信息;详情见_example文件 使用 go mod -u github.com/one-gold-coin/validator

One Gold Coin 2 Sep 30, 2021
Data validators for Golang

golidators Golidators is a golang package, it includes basic data validation functions and regexes. Install go get github.com/eredotpkfr/golidators Ov

Erdoğan Yoksul 10 Oct 19, 2022