Custom Rule - Input Object

Introduction

You may have noticed that when we specify a struct, our rules can only validate its key-values or attributes. If we want to use the rules to completely validate the struct object, we find that we cannot register custom validation rules for the validation component. However, our validation component also supports directly validating the current struct object. Let‘s look at an example where we need to perform complete custom validation on a user creation request and register a validation rule for UserCreateReq to achieve this.

Usage Example

package main

import (
    "context"
    "fmt"
    "github.com/gogf/gf/v2/database/gdb"
    "github.com/gogf/gf/v2/errors/gerror"
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gctx"
    "github.com/gogf/gf/v2/util/gvalid"
    "time"
)

type UserCreateReq struct {
    g.Meta `v:"UserCreateReq"`
    Name   string
    Pass   string
}

func RuleUserCreateReq(ctx context.Context, in gvalid.RuleFuncInput) error {
    var req *UserCreateReq
    if err := in.Data.Scan(&req); err != nil {
        return gerror.Wrap(err, `Scan data to UserCreateReq failed`)
    }
    // SELECT COUNT(*) FROM `user` WHERE `name` = xxx
    count, err := g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
        Duration: time.Hour,
        Name:     "",
        Force:    false,
    }).Where("name", req.Name).Count()
    if err != nil {
        return err
    }
    if count > 0 {
        return gerror.Newf(`The name "%s" is already taken by others`, req.Name)
    }
    return nil
}

func main() {
    var (
        ctx  = gctx.New()
        user = &UserCreateReq{
            Name: "john",
            Pass: "123456",
        }
    )
    err := g.Validator().RuleFunc("UserCreateReq", RuleUserCreateReq).Data(user).Run(ctx)
    fmt.Println(err)
}

As you can see, by embedding g.Meta metadata into the struct and binding the custom rule UserCreateReq, when we validate the struct object through CheckStruct, we can use UserCreateReq to achieve validation.

After executing the above example, the terminal output:

The name "john" is already taken