go-map-validator

module
v0.0.29 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 15, 2024 License: MIT

README ΒΆ

Simple Validator using struct properties as rules

You can integrate with all golang framework using http.Request interface

examples : https://github.com/Rhyanz46/go-map-validator/tree/main/test

Install
go get github.com/Rhyanz46/go-map-validator/map_validator
discussion or updates

Features

  • validate value in map[string]interface{} by keys
  • validate data from http.Request json/multipart
    • support file upload
  • Unique Value
    • ex case : old_password and new_password cant be using same value
  • RequiredWithout check
    • ex case : the field flavor is required if custom_flavor is null
  • enum value check
  • min/max length data check
  • email field check
  • uuid field check
  • IPv4 field check
  • IPv4 Network check
  • regex on string validation
  • nested validation πŸ”₯
  • you can create your own extension πŸ”₯πŸ”₯πŸ”₯πŸ”₯ (example : https://github.com/Rhyanz46/go-map-validator/example_extensions/)
  • custom message :
    • on invalid regex message : βœ… ready
    • on type not match message : βœ… ready
    • on min/max data message : βœ… ready
    • on null data message : βŒ› not ready
    • on unique values error : βŒ› not ready
    • on enum value not match : βŒ› not ready
    • on RequiredWithout error : βŒ› not ready

On Progress

  • validation for one data value only

Custom Message Variables

No Variable Name
1 ${field}
2 ${expected_type}
3 ${actual_type}
4 ${actual_length}
5 ${expected_min_length}
6 ${expected_max_length}

Road Map

  • get from urls params http
  • validation for base64
  • handle file size on multipart
  • extension for generate OpenAPI Spec that support with this package
  • image resolution validation
  • multi validation on one field (ex : IPv4: true, UUID: true)

example :

Example 1
payload := map[string]interface{}{"jenis_kelamin": "laki-laki", "hoby": "Main PS", "umur": 1, "menikah": true}
err := map_validator.NewValidateBuilder().SetRules(map_validator.RulesWrapper{
        Rules: map[string]map_validator.Rules{
            "jenis_kelamin": {Enum: &map_validator.EnumField[any]{Items: []string{"laki-laki", "perempuan"}}},
            "hoby":          {Type: reflect.String, Null: false},
            "menikah":       {Type: reflect.Bool, Null: false},
        },
    },
).Load(payload).RunValidate()
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}

err = map_validator.NewValidateBuilder().SetRules(map_validator.RulesWrapper{
        Rules: map[string]map_validator.Rules{
            "jenis_kelamin": {Enum: &map_validator.EnumField[any]{Items: []string{"laki-laki", "perempuan"}}},
            "hoby":          {Type: reflect.Int, Null: false},
            "menikah":       {Type: reflect.Bool, Null: false},
        },
    },
).Load(payload).RunValidate()
if err == nil {
    t.Error("Expected have an error, but you got no error")
}
Example 2 ( Nested Object Validation )
filterRole := map[string]map_validator.Rules{
    "search":          {Type: reflect.String, Null: true},
    "organization_id": {UUID: true, Null: true},
}
jsonDataRoles := map_validator.NewValidateBuilder().StrictKeys().SetRules(map_validator.RulesWrapper{
    Rules: map[string]map_validator.Rules{
        "filter":        {Object: &filterRole, Null: true},
        "rows_per_page": {Type: reflect.Int64, Null: true},
        "page_index":    {Type: reflect.Int64, Null: true},
        "sort": {
            Null:   true,
            IfNull: "FULL_NAME:DESC",
            Type:   reflect.String, Enum: &map_validator.EnumField[any]{
            Items: []string{"FULL_NAME:DESC", "FULL_NAME:ASC", "EMAIL:ASC", "EMAIL:DESC"},
      },
    },
}
})

image

Example 3 ( Echo Framework )
func handleLogin(c echo.Context) error {
    jsonHttp, err := map_validator.NewValidateBuilder().SetRules(map_validator.RulesWrapper{
        Rules: map[string]map_validator.Rules{
            "email":    {Email: true, Max: map_validator.SetTotal(100)},
            "password": {Type: reflect.String, Min: map_validator.SetTotal(6), Max: map_validator.SetTotal(30)},
        },
    }).LoadJsonHttp(c.Request())
    if err != nil {
        return c.JSON(http.StatusBadRequest, err)
    }
    err = jsonHttp.RunValidate()
    if err != nil {
        return c.JSON(http.StatusBadRequest, err)
    }
    return c.NoContent(http.StatusOK)
}

func main() {
    e := echo.New()
    e.POST("/login", handleLogin)
    e.Start(":3000")
}

Example 4 ( Bind To Struct )
type Data struct {
    JK      string `map_validator:"jenis_kelamin"`
    Hoby    string `map_validator:"hoby"`
    Menikah bool   `map_validator:"menikah"`
}

payload := map[string]interface{}{"jenis_kelamin": "laki-laki", "hoby": "Main PS", "umur": 1, "menikah": true}
err := map_validator.NewValidateBuilder().SetRules(map_validator.RulesWrapper{
    Rules: map[string]map_validator.Rules{
        "jenis_kelamin": {Enum: &map_validator.EnumField[any]{Items: []string{"laki-laki", "perempuan"}}},
        "hoby":          {Type: reflect.String, Null: false},
        "menikah":       {Type: reflect.Bool, Null: false},
    },
}).Load(payload).RunValidate()
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}

testBind := &Data{}
if testBind.JK != "" {
    t.Errorf("Expected : '' But you got : %s", testBind.JK)
}
err = extraCheck.Bind(testBind)
if err != nil {
    t.Errorf("Error : %s ", err)
}

if testBind.JK != payload["jenis_kelamin"] {
    t.Errorf("Expected : %s But you got : %s", payload["jenis_kelamin"], testBind.JK)
}

Example 5 ( Custom message )
payload := map[string]interface{}{"total": 12, "unit": "KG"}
validRole := map_validator.RulesWrapper{
    Rules: map[string]map_validator.Rules{
        "total": {
            Type: reflect.Int,
            CustomMsg: map_validator.CustomMsg{
                OnTypeNotMatch: map_validator.SetMessage("Total must be a number, but your input is ${actual_type}"),
            },
        },
    },
}

check, err := map_validator.NewValidateBuilder().SetRules(validRole).Load(payload)
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}
_, err = check.RunValidate()
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}

Example 6 ( Regex validator )
payload := map[string]interface{}{"hp": "+62567888", "email": "dev@ariansaputra.com"}
validRole := map_validator.RulesWrapper{
    Rules: map[string]map_validator.Rules{
        "hp":    {RegexString: `^\+(?:\d{2}[- ]?\d{6}|\d{11})$`},
        "email": {RegexString: `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`},
    },
}
check, err := map_validator.NewValidateBuilder().SetRules(validRole).Load(payload)
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}
_, err = check.RunValidate()
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
}

Example 7 ( Unique value )
role := map_validator.RulesWrapper{
    Rules: map[string]map_validator.Rules{
        "password":     {Type: reflect.String, Unique: []string{"password"}, Null: true},
        "new_password": {Type: reflect.String, Unique: []string{"password"}, Null: true},
    },
}
payload := map[string]interface{}{
    "password":     "sabalong",
    "new_password": "sabalong",
}
check, err := map_validator.NewValidateBuilder().SetRules(role).Load(payload)
if err != nil {
    t.Errorf("Expected not have error, but got error : %s", err)
    return
}
expected := "value of 'password' and 'new_password' fields must be different"
_, err = check.RunValidate()
if err.Error() != expected {
    t.Errorf("Expected :%s. But you got : %s", expected, err)
}

Directories ΒΆ

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL