Code Monkey home page Code Monkey logo

govalidator's Introduction

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

License

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

govalidator's People

Contributors

amjustdoit avatar bluele avatar erickskrauch avatar ivan-feofanov avatar kveselkov avatar maoueh avatar paralax avatar rexskz avatar s4kibs4mi avatar stevehill1981 avatar thedevsaddam avatar theruziev avatar tiagoacardoso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

govalidator's Issues

send params to govalidator custom messages

rules := govalidator.MapData{
		"title": 		[]string{"required"},
		"description":    []string{"required", "min:4", "max:20"},
		"file:image":    []string{ "mime:image/jpg,image/png"},
		"file:file":    []string{ "mime:video/mp4","size:1000"},
	}

	messages := govalidator.MapData{
		"title": []string{"required: Is Required"},
		"description":    []string{"required: Is Required","max: must be %d chars maximum"},
		"file:image": []string{"required: Is Required"},
		"file:file": []string{"required: Is Required"},
	}

	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
	}
	vgov := govalidator.New(opts)
	return vgov.Validate()

if we want send params to custom messages we have to write params statically
but if you change rules.go file like this , we can send any params to custom messages

i change max rule for example

AddCustomRule("max", func(field string, rule string, message string, value interface{}) error {
		mustLen := strings.TrimPrefix(rule, "max:")
		lenInt, err := strconv.Atoi(mustLen)
		if err != nil {
			panic(errStringToInt)
		}
		lenFloat, err := strconv.ParseFloat(mustLen, 64)
		if err != nil {
			panic(errStringToFloat)
		}
		errMsg := fmt.Errorf("The %s field value can not be greater than %d", field, lenInt)
		if message != "" {
			errMsg = fmt.Errorf(message, lenInt)
		}
		errMsgFloat := fmt.Errorf("The %s field value can not be greater than %f", field, lenFloat)
		if message != "" {
			errMsgFloat = fmt.Errorf(message, lenFloat)
		}
		rv := reflect.ValueOf(value)
		switch rv.Kind() {
		case reflect.String:
			inLen := rv.Len()
			if inLen > lenInt {
				if message != "" {
					return fmt.Errorf(message, lenInt)
				}
				return fmt.Errorf("The %s field must be maximum %d char", field, lenInt)
			}
...

overflow issue in golang playground

I copied the direct validation example to the playground https://play.golang.org/p/ygjhVZg59cf
and I got the following error:

go: finding github.com/thedevsaddam/govalidator v1.9.8
go: downloading github.com/thedevsaddam/govalidator v1.9.8
go: extracting github.com/thedevsaddam/govalidator v1.9.8
# github.com/thedevsaddam/govalidator
../gopath075688560/pkg/mod/github.com/thedevsaddam/[email protected]/rules.go:899:7: constant -9223372036854775808 overflows int
../gopath075688560/pkg/mod/github.com/thedevsaddam/[email protected]/rules.go:908:7: constant 9223372036854775807 overflows int

I do not know whether it is a general problem or only inside of the playground, but changing from math.MinInt64 to math.MinInt32 and math.MaxInt64 to math.MaxInt32 solved it.

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
} 

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

Cannot read body after JSON validation

The body cannot be retrieved after a JSON Validation. The only way to get it is to use v.Opts.Data.

The following line in the JSON validation code drains the request's body reader, rendering it unusable:

err := json.NewDecoder(v.Opts.Request.Body).Decode(v.Opts.Data)

Proposed solution: reset the read state after validation.

Current workaround:

var errors url.Values
var bodyBytes []byte
if r.Body != nil {
	bodyBytes, _ = ioutil.ReadAll(r.Body)
	validator.Opts.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
	errors = validator.ValidateJSON()
	validator.Opts.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
}

i want validator data 2 level

{
"title": {
"th": "en", #required
"en": "th" #required
"name": "xxxxxxx", #required
},
"name": "xxxxxxx", #required
"email":"[email protected]"
}
i want validate filed title>name and filed name outside

how must imprement ?
plz Thx

Fields with string base types cannot be optional

The use case I'm presenting is what I'd consider the current-conventional use case. We're not submitting a form/url-encoded to the api end point, but rather posting application/json. Thus to validate the request, we have to pass a Go struct defining the data to the validator. When unmarshalling the JSON, all string fields on the struct will be assigned "" (empty string) if no value is present in the post body's JSON. This brings us to the various alpha* validation rules and "required".

The problem is that empty string fails every string rule even when "required" isn't set as a rule on a field.

How should we approach this?

Support Date Time

Currently, when attempting to validate a date such as "2019/09/05 12:49:01" as a date, we get an (expected) validation error. There is no support for a date time object currently outside of using a regex validation. This would be a nice feature.

Suggestion: use struct tags

Instead of "duplicating" the struct with code like

	rules := govalidator.MapData{
		"username": []string{"required", "between:3,5"},
		"email":    []string{"required", "min:4", "max:20", "email"},
		"web":      []string{"url"},
		"age":      []string{"numeric_between:18,56"},
	}

you could put the rules in the struct and use reflection:

type user struct {
	Username string `json:"username"  validate:"required,between:3,5"`
	Email    string `json:"email"     validate:"required,min:4,max:20,email"`
	Web      string `json:"web"       validate:"url"`
	Age      int    `json:"age"       validate:"numeric_between:18,56"`
}

An example of this can be found in this gist.

Gocritic 3.3 warning typeSwitchVar

Find using https://go-critic.github.io/overview#typeSwitchVar-ref

$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 0 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 1 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 2 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 3 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 4 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 5 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 6 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 7 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 8 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 9 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 10 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 11 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 12 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 13 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 14 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:183:2: typeSwitchVar: case 15 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 0 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 1 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 2 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 3 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 4 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 5 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 6 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 7 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 8 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 9 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 10 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 11 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 12 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 13 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 14 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/roller.go:198:6: typeSwitchVar: case 15 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 1 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 2 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 3 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 4 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 5 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 6 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 7 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 8 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 9 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 10 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 11 can benefit from type switch with assignment
$GOPATH/src/github.com/thedevsaddam/govalidator/rules.go:230:3: typeSwitchVar: case 12 can benefit from type switch with assignment

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"

How to validate slice of struct field

If I have struct like this:

type Contact struct {
	Type string `json:"type"`
	Value string `json:"value"`
}

type User struct {
	Name string `json:"name"`
	Contacts []Contact `json:"contacts"`
}

How to validate contact Type and value?

Validating numeric field with value 0

When validating a field with rule "required" and "numeric", when the value of 0 is provided, required validation error is trigered.

Go version: 1.9
Framework: echo
Here is an example

Json struct

type serviceRequest struct {
Owner string json:"owner"
Service int json:"service"
Operation string json:"operation"
AgentTransaction string json:"ati"
}

Here is the request handling function

func AgentServiceAction(c echo.Context) (err error) {

var structure serviceRequest
rules := govalidator.MapData{
	"owner":     []string{"required", "between:10,16"},
	"service":   []string{"required", "numeric"},
	"operation": []string{"required", "in:start,confirm,check"},
	"ati":       []string{"required", "alpha_num", "max:64", "min:1"},
}
opts := govalidator.Options{
	Request: c.Request(), // request object
	Data:    &structure,  //Structure to validate
	Rules:   rules,       // rules map
}

v := govalidator.New(opts)
e := v.ValidateJSON()

fmt.Println(v)
fmt.Println(e)

verr := map[string]interface{}{"validationError": e}

return c.JSON(200, response.JsonResponse{
	Code:    300,
	Message: "All good!",
	Data:    verr,
})

}

Post data:

{
"ati":"324t5fc45w6bh6r7unr758rtinr67",
"operation":"start",
"owner":"871029399119",
"service":0
}

The received response:

{
"code": 300,
"success": false,
"message": "All good!",
"data": {
"validationError": {
"service": [
"The service field is required"
]
}
}
}

Failed ValidateStruct, field of type 'int' not validate as numeric

Hi there.
It seems a bug when validate a field of type 'int/uint'

type Foo struct {
        Field uint  'json:"field"'
}

struct1 = &Foo{Field: 12345}

rules := govalidator.MapData{
        "field": []string{"required", "numeric"},
    }

opts := govalidator.Options{
        Data:  struct1,
        Rules: rules,
        RequiredDefault: true,
    }
v := govalidator.New(opts)
errs := v.ValidateStruct()

in the file rules.go:856 runs the 'numeric validate func'. inside it, calling function toString from file utils.go:37
image

and here incorrect convert int to string
image
(PS: my English is bad)

File Validation Not Working

Dear brother
i use this code for file upload validation . but its always show

{
    "validationError": {
        "photo": [
            "Photo is required"
        ]
    }
}

Whatever i put file or not . I just copy and past your file validation code form documentation .

Bail on first error

Would it be possible to return the error bag on the first failure as opposed to running all the rules.

  1. Bail when the first rule in a ruleset for a field fails
    example:
rules := govalidator.MapData{
		"email": []string{"required"},
		"password": []string{"required"},
		"some_field": []string{"bail", "required", "in:something,somethingelse"},
	}
  1. Bail when the first rule for the entire validation fails.
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
                 BailFirstError: true //returns the error bag with only one item
	}

Error return is not consistently sort?

rules := govalidator.MapData{
	"name": []string{"required"},
	"email":    []string{"required"},
	"password":      []string{"required"},
}


opts := govalidator.Options{
	Request:         r,        // request object
	Rules:           rules,    // rules map
	RequiredDefault: true,     // all the field to be pass the rules
}

v := govalidator.New(opts)
e := v.Validate()
err := map[string]interface{}{"validationError": e}

fmt.Println(err)

here is what i got after couple of run:

map[validationError:map[password:[The password field is required] name:[The name field is required] email:[The email field is required]]]

map[validationError:map[name:[The name field is required] email:[The email field is required] password:[The password field is required]]]

map[validationError:map[name:[The name field is required] email:[The email field is required] password:[The password field is required]]]

map[validationError:map[email:[The email field is required] password:[The password field is required] name:[The name field is required]]]

map[validationError:map[password:[The password field is required] name:[The name field is required] email:[The email field is required]]] 

Proposal to change internal error handling

I think govalidator should distinguish validation errors and internal errors, currently, it populates the url.Values return value map for every kind of error.

I've ran into the following issue today:
map[_error:[json: cannot unmarshal string into Go struct field createProductValidation.price of type int]]
I think this should rather be returned as an individual error than populating the url.Values.

Currently, the Validate function returns url.Values but it should rather return (url.Values, error) and if any error happens it could be handled in the http.Handler.

What do you think?

Examples should include idiomatic error handling

In your examples, the whole point was to show error validation errors, but in real-world applications, it's rarely the use case. As a GO API developer, I'm not sure how to handle empty validation error maps.

Please let me know if you think it's a good example and I could add them to a PR. 😄

	err := v.ValidateJSON()
	if err.Get("_error") != "" {
		log.Print(err)
		http.Error(w, "Error happened processing the request", http.StatusInternalServerError)
		return

	}
	if len(err) != 0 {
		validationErr := map[string]interface{}{"validationError": err}
		json.NewEncoder(w).Encode(validationErr)
		return
	}

Min/Max rules confusingly named

Just tried to use the min rule to validate that my numeric input was greater than 1000000000000000, only to discover that the rule is actually looking for the number of characters instead.

max is along the same lines.

I feel like these should be called minlength and maxlength instead, but that would probably break things for people who are already using the library.

What do you think about introducing minval and maxval instead? It would only work for ints and floats.

An alternative could be to relax the definition of numeric_between, so that you can omit either the first or second range values to have them default to whatever the smallest and largest values are that Go allows (not sure how to get those, yet - I'm new to Go).

Let me know how you'd prefer to proceed and I'll make a PR :)

date validation fails for date:dd-mm-yyyy.

// Date check the provided field is valid Date
AddCustomRule("date", func(field string, rule string, message string, value interface{}) error {
	str := toString(value)
	if rule == "date:dd-mm-yyyy" {
		if !isDateDDMMYY(str) {
			if message != "" {
				return errors.New(message)
			}
			return fmt.Errorf("The %s field must be a valid date format. e.g: dd-mm-yyyy, dd/mm/yyyy etc", field)
		}
	}
	if !isDate(str) {
		if message != "" {
			return errors.New(message)
		}
		return fmt.Errorf("The %s field must be a valid date format. e.g: yyyy-mm-dd, yyyy/mm/dd etc", field)
	}
	return nil
})

This is inherently flawed, when the following check passes without any error it should return from there,

		if rule == "date:dd-mm-yyyy" {
		if !isDateDDMMYY(str) {
			if message != "" {
				return errors.New(message)
			}
			return fmt.Errorf("The %s field must be a valid date format. e.g: dd-mm-yyyy, dd/mm/yyyy etc", field)
		}
	}

instead it does the second check too

	if !isDate(str) {
		if message != "" {
			return errors.New(message)
		}
		return fmt.Errorf("The %s field must be a valid date format. e.g: yyyy-mm-dd, yyyy/mm/dd etc", field)
	}
	return nil
})

A better solution would be

// Date check the provided field is valid Date
AddCustomRule("date", func(field string, rule string, message string, value interface{}) error {
	str := toString(value)

	switch rule {
	case "date:dd-mm-yyyy":
		if !isDateDDMMYY(str) {
			if message != "" {
				return errors.New(message)
			}
			return fmt.Errorf("The %s field must be a valid date format. e.g: dd-mm-yyyy, dd/mm/yyyy etc", field)
		}
	default:
		if !isDate(str) {
			if message != "" {
				return errors.New(message)
			}
			return fmt.Errorf("The %s field must be a valid date format. e.g: yyyy-mm-dd, yyyy/mm/dd etc", field)
		}
	}
	return nil
})

Require integer to exist and let it equal 0

Hi, thanks for this great library! So I know that the 'required' struct tag raises an error if you provide an integer that equals 0.

I know why this is the case -- the zero value for integers is, well, 0, so it's impossible to tell whether a value is 0 because it's missing or because it's provided and its actually 0. To error on the side of caution, govalidator decided to not allow 0 values for integers.

If I wanted to write a custom rule, however, that required a struct to have a certain integer field, which is allowed to be 0, how would I go about doing that? Any advice?

reflect: call of reflect.Value.Type on zero Value

2017/10/14 21:53:24 http: panic serving [::1]:51539: reflect: call of reflect.Value.Type on zero Value
goroutine 50 [running]:
net/http.(*conn).serve.func1(0xc420175680)
	/usr/local/Cellar/go/1.9/libexec/src/net/http/server.go:1697 +0xd0
panic(0x14ae000, 0xc420228820)
	/usr/local/Cellar/go/1.9/libexec/src/runtime/panic.go:491 +0x283
reflect.Value.Type(0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.9/libexec/src/reflect/value.go:1688 +0x1a3
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004f7c8, 0x1533a00, 0xc42012a640)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:114 +0x772
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004f7c8, 0x14f5020, 0xc42012a630)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:106 +0x30a
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004f7c8, 0x1504620, 0xc42012a630)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:106 +0x30a
github.com/thedevsaddam/govalidator.(*roller).start(0xc42004f7c8, 0x150df40, 0xc42012a5a0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:40 +0x310
github.com/thedevsaddam/govalidator.(*Validator).ValidateJSON(0xc42004fa20, 0x0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/validator.go:146 +0x2a5

Custom Validator Duplicate Entry Error when Resubmitting the Form :)

Hi Saddam,
I am trying to create a custom validation rule. It works great when I submit the form first time. But after changing the value for form field when I resubmit the again it shows me:

 http: panic serving [::1]:57565: validator: password_confirmed is already defined in rules
goroutine 26 [running]:
net/http.(*conn).serve.func1(0xc4203b6000)
        /usr/local/go/src/net/http/server.go:1697 +0xd0
panic(0x13ecf40, 0xc420268c80)
        /usr/local/go/src/runtime/panic.go:491 +0x283
github.com/thedevsaddam/govalidator.AddCustomRule(0x1473f19, 0x12, 0xc420268c60)
        /Users/rbrahul/go/src/github.com/thedevsaddam/govalidator/rules.go:22 +0x154
main.createUser(0x1671740, 0xc42039a0e0, 0xc42026bd00)
        /Users/rbrahul/Projects/go/src/users/userHandlers.go:364 +0xca
net/http.HandlerFunc.ServeHTTP(0x148b688, 0x1671740, 0xc42039a0e0, 0xc42026bd00)
        /usr/local/go/src/net/http/server.go:1918 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc42031e000, 0x1671740, 0xc42039a0e0, 0xc42026bd00)
        /Users/rbrahul/go/src/github.com/gorilla/mux/mux.go:159 +0xed
net/http.serverHandler.ServeHTTP(0xc420296a90, 0x1671740, 0xc42039a0e0, 0xc42026bb00)
        /usr/local/go/src/net/http/server.go:2619 +0xb4
net/http.(*conn).serve(0xc4203b6000, 0x1671e00, 0xc420259dc0)
        /usr/local/go/src/net/http/server.go:1801 +0x71d
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2720 +0x288

And here is my source code:

...
govalidator.AddCustomRule("password_confirmed", func(field string, rule string, message string, value interface{}) error {
		fmt.Println("Val ", req.PostFormValue(field))
		if req.PostFormValue(field) != req.PostFormValue("password") {
			return fmt.Errorf("Field %s is miss matched with password", field)
		}
		return nil
	})
...

Hi everyone, who's using govalidator in production?

Hello everyone, I'm just curious any companies or individual using govalidator in production? If you see the post please share with us, I'd like to include their list in Readme. It'll be inspiring to hear from you.

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.

Required on "map" are not working

Hi there!

Today I just found out that for example map[string]string
Just had a look on the source code but my knowledge is not enough to solve the problem.
Even adding a CustomRule it doesn't work, seems to be an internal problem in the source code.

Code:

func validate(c *gin.Context) {
	type Example struct {
		Foo string            `json:"foo"`
		Bar map[string]string `json:"bar"`
	}

	rules :=
		govalidator.MapData{
			"foo": []string{"required"},
			"bar": []string{"required"},
		}

	var ex Example
	opts := govalidator.Options{
		Request: c.Request,
		Rules:   rules,
		Data:    &ex,
	}
	v := govalidator.New(opts)
	e := v.ValidateJSON()
	if len(e) > 0 {
		validationErrors := map[string]interface{}{"validation_errors": e}
		c.JSON(http.StatusBadRequest, validationErrors)
		return
	}
}

Input:

{
    "foo": "asd",
    "bar": {
    	"1": "one"
    }
}

Output:

{
    "validation_errors": {
        "bar": [
            "The bar field is required"
        ]
    }
}

Best regards :)

Validate array of string

I have an array of strings from my JSON, for which I would like to validate each string field.

Looks like rules such as userValues: []string{"required", "alpha"}, fails despite the field being valid.

How can I handle this case?

RequiredDefault = false works wrong with files

Implementation of the keepRequiredField() works fine with the form's data, but it doesn't take into consideration fields with files.

For example, I want to have some endpoint, where the user can update their profile information and upload a new avatar. But avatar is optional and I want to validate it only in the case when it is uploaded.

Validating request body always returns error

I'm trying to use govalidator and it always returns error even if i send the correct data, may i'm doing it wrong because this is my first time using this package.

package notifier

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

	"github.com/thedevsaddam/govalidator"
)

// Payload is request data structure expected
type Payload struct {
	TransactionReference    string              `json:"transactionReference"`
	Timestamp                    string               `json:"timestamp"`
	ItemID                           string               `json:"itemId"`
	AmountPaid                  govalidator.Int `json:"amountPaid"`
	Status                            string               `json:"status"`
}

type res struct {
	Message string `json:"message"`
	Data    *Payload
}

// UpdatePayment Receives payment details and sends to accounting API
func UpdatePayment(w http.ResponseWriter, r *http.Request) {
	p := new(Payload)

	opts := govalidator.Options{
		Request:         r,
		Data:            &p,
		Rules:           rules,
		RequiredDefault: true,
	}

	req := govalidator.New(opts)
	e := req.Validate()

	if len(e) > 0 {
		validationErr := map[string]interface{}{"data": e, "status": "error"}
		json.NewEncoder(w).Encode(validationErr)
		return
	}

	retMsg := &res{
		Message: "Payment notification recieved",
		Data:    p,
	}

	json.NewEncoder(w).Encode(retMsg)
}

second file valitadions.go

package notifier

import "github.com/thedevsaddam/govalidator"

var rules = govalidator.MapData{
	"amountPaid":                  []string{"required", "numeric"},
	"timestamp":                    []string{"required", "date"},
	"transactionReference":   []string{"required"},
	"itemId":                          []string{"required"},
	"status":                           []string{"required"},
}

Having panic for unexported field or method

2017/10/14 05:35:40 http: panic serving [::1]:57728: reflect.Value.Interface: cannot return value obtained from unexported field or method
goroutine 6 [running]:
net/http.(*conn).serve.func1(0xc420175220)
	/usr/local/Cellar/go/1.9/libexec/src/net/http/server.go:1697 +0xd0
panic(0x148d800, 0x159f730)
	/usr/local/Cellar/go/1.9/libexec/src/runtime/panic.go:491 +0x283
reflect.valueInterface(0x148da80, 0xc4202621c0, 0xab, 0x1533801, 0x1445372, 0x9)
	/usr/local/Cellar/go/1.9/libexec/src/reflect/value.go:936 +0x1dd
reflect.Value.Interface(0x148da80, 0xc4202621c0, 0xab, 0x4, 0x0)
	/usr/local/Cellar/go/1.9/libexec/src/reflect/value.go:925 +0x44
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004b7c8, 0x1533860, 0xc4202621c0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:121 +0x54e
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004b7c8, 0x14f4e80, 0xc4202621b0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:98 +0x2da
github.com/thedevsaddam/govalidator.(*roller).traverseStruct(0xc42004b7c8, 0x1504480, 0xc4202621b0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:98 +0x2da
github.com/thedevsaddam/govalidator.(*roller).start(0xc42004b7c8, 0x150dda0, 0xc420262120)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/roller.go:38 +0x1c6
github.com/thedevsaddam/govalidator.(*Validator).ValidateJSON(0xc42004ba20, 0x0)
	/Users/s4kib/go/src/github.com/thedevsaddam/govalidator/validator.go:146 +0x2a5

1000000 or more is not validate as numeric

I'm using Echo framework and have an issue with numeric ( and also numeric_between ) rule. I'm applying this within handler with POST method and json as input.

Bug I'm reporting is the amount validation always failed when bigger or equal to 1000000 (million). Amount definitely in numeric, this strange behaviour is also apllied with numeric_between.

The validation work fine when the amount value is less than 1000000.

version = "v1.9.2"
last commit = "cf8445ca81206fc6c8a231f9b7ff8eecf0fd4cdf"

Input :

{
  "merchant_id": 1,
  "amount": 1000000,
  "requestor": "Whoami",
  "notes": "My notes"
}

response :

{
	"validation_errors": {
		"amount": [
			"The amount field must be numeric"
		]
	}
}

Below is my codes :

func MyHandler(c echo.Context) error {
	type (
		ReqBody struct {
			MerchantID uint64  `json:"merchant_id"`
			Amount     float64 `json:"amount"`
			Requestor  string  `json:"requestor"`
			Notes      string  `json:"notes"`
		}
	)

	req := ReqBody{}

	// ========================= GET THE RAW JSON AND MINIFY IT FOR RAW SIGNATURE VERIFICATION
	// Read the Body content
	bodyBytes, err := ioutil.ReadAll(c.Request().Body)
	if err != nil {
		return c.JSON(http.StatusBadRequest, err)
	}

	// Restore the io.ReadCloser to its original state
	c.Request().Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

	// ======== VALIDATE REQUEST
	rules := govalidator.MapData{
		"merchant_id": []string{"required"},
		"amount":      []string{"required", "numeric"},
		"requestor":   []string{"required", "max:100"},
		"notes":       []string{"max:255"},
	}

	vld := ValidateRequest(c, rules, &req)
	if vld != nil {
		return c.JSON(http.StatusBadRequest, "BAD REQUEST")
	}

	defer c.Request().Body.Close()

	return c.JSON(http.StatusOK, "OK")
}

func ValidateRequest(c echo.Context, rules govalidator.MapData, data interface{}) map[string]interface{} {
	var err map[string]interface{}

	opts := govalidator.Options{
		Request: c.Request(),
		Data:    data,
		Rules:   rules,
	}

	v := govalidator.New(opts)

	e := v.ValidateJSON()

	if len(e) > 0 {
		err = map[string]interface{}{"validation_errors": e}
	}

	return err
}

How can I cater for the case of conditional "required" ?

Hi.

I have a use case, for which I don't know how to set the flags from the validator.

Those are the required fields

{ "title": "This is the title", "caption": "This is the caption" }

title: []string{"required"}, caption: []string{"required"}

Now there may be a nested structure as such. The "attached_media" key is NOT required in the payload, BUT IF it is provided, then only some fields are required.

{ "title": "This is the title", "caption": "This is the caption", "attached_media": { "Yo": "Plop" } }

So this is my attempt at the settings, which fails,
title: []string{"required"}, caption: []string{"required"}` Yo: []string{"required"}

Bottom line, how can I set things u so that some nested keys are required ONLY if the parent key is there ?

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

how to valide a multiple nested struct

Im trying to valide this struct, my data is a object with 1 object property, this one can have multiple objects with its own propertys, when i send the data, the govalidator respond with an error
2
3
1

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 ?

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

How to validate array of input with same name

 <form method="post" name="myform" action="http://localhost:8081/post" >
     <input type="checkbox" name="product" value="Apple" />
     <input type="checkbox" name="product" value="Orange" />
     <input type="checkbox" name="product" value="Grape" />
     <input type="submit">
</form>

How can i validate a form input with same name?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.