RRuna

数据验证

请求输入验证和字段错误

Runa 的验证能力由 validate 工具包提供。它用普通 Go 代码声明规则,不依赖隐式 tag,字段规则更容易读,也更容易测试。

安装

go get github.com/duxweb/runa/validate

独立使用

type CreateUserInput struct {
    Name  string
    Email string
}

input := &CreateUserInput{Name: "Runa", Email: "hello@example.com"}

v := validate.New(input, nil)
v.Field("Name").Required("请输入名称").MinLen(2, "名称至少 2 个字符")
v.Field("Email").Required("请输入邮箱").Email("邮箱格式不正确")

if err := v.Run(); err != nil {
    return err
}

Field("Name") 里的 Name 是 Go 结构体字段名,不是 JSON 字段名。

在强类型路由中使用

输入结构体实现 Validate 方法后,强类型路由会自动调用它。

type CreateUserInput struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

func (input *CreateUserInput) Validate(v *validate.Validator) {
    v.Field("Name").Required("请输入名称").MinLen(2, "名称至少 2 个字符")
    v.Field("Email").Required("请输入邮箱").Email("邮箱格式不正确")
}

route.Post[CreateUserInput, UserOutput](
    route.Default(),
    "/users",
    func(ctx *route.Context, input *CreateUserInput) (*UserOutput, error) {
        return &UserOutput{Name: input.Name}, nil
    },
)

在 CRUD 中使用

crud.New[User, UserQuery](res, store).
    Validate(func(c *crud.Context[User], v *validate.Validator) {
        v.Field("Name").Required("请输入名称").MinLen(2, "名称至少 2 个字符")
    })

常见规则

规则 说明
Required(message) 要求字段非空
Min(value, message) 数值不能小于 value
Max(value, message) 数值不能大于 value
MinLen(value, message) 字符长度不能小于 value
MaxLen(value, message) 字符长度不能大于 value
Email(message) 校验邮箱格式
Regex(pattern, message) 校验正则表达式
Call(handler) 添加字段级回调
Check(handler) 添加输入级回调

字段级回调

v.Field("Name").Call(func(value string) error {
    if value == "admin" {
        return errors.New("名称不能使用 admin")
    }
    return nil
})

输入级回调

v.Check(func() error {
    if input.Name == input.Email {
        return errors.New("名称不能和邮箱相同")
    }
    return nil
})

错误格式

验证失败会返回 validate.ValidationError,可以用:

if item := validate.AsError(err); item != nil {
    for _, field := range item.Errors {
        fmt.Println(field.Field, field.Message)
    }
}

常见错误

Field 里写了 json 名称

不要写 Field("name"),应该写 Go 字段名 Field("Name")

忘记 Run

独立使用时必须调用 v.Run()。强类型路由里由框架自动调用。

规则缺少 message

当前规则方法都需要 message 参数,例如 Required("请输入名称")

编辑此页