golang数据绑定与验证插件库gbind的使用

golang数据绑定与验证插件库gbind的使用

gbind是一个封装通用参数解析和参数验证逻辑的Go库,可以最小化日常开发中的重复代码,用几行代码解决参数绑定和验证问题。

特性

  • 基于tag信息将数据绑定到指定结构体

    • 内置HTTP请求路径、查询参数、表单、header、cookie绑定能力
    • 内置json绑定能力,使用encoding/json实现
    • 支持设置绑定字段的默认值
    • 支持自定义绑定解析逻辑
  • 根据tag信息验证字段值

使用示例

HTTP API请求参数绑定与验证

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"github.com/bdjimmy/gbind"
)

type Params struct {
	API    string `gbind:"http.path,default=/api/test"`
	Appkey string `gbind:"http.query.appkey,default=appkey-default"`
	Page   int    `gbind:"http.query.page,default=1"`
	Size   int    `gbind:"http.query.size,default=10"`
	Token  string `gbind:"http.cookie.Token" validate:"required" err_msg:"please login"`
	Host   string `gbind:"http.header.host,default=www.baidu.com"`
	Uids   []int  `gbind:"http.form.uids"`
}

func Controller(w http.ResponseWriter, r *http.Request) {
	var requestParams = &Params{}
	if _, err := gbind.BindWithValidate(context.Background(), requestParams, r); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	bs, _ := json.MarshalIndent(requestParams, "", "\t")
	w.Write(bs)
}

func main() {
	w := httptest.NewRecorder()
	u, _ := url.Parse("http://gbind.baidu.com/api/test?appkey=abc&page=2")
	r := &http.Request{
		Method: http.MethodPost,
		Header: map[string][]string{
			"Host": {"gbind.baidu.com"},
		},
		PostForm: url.Values{
			"uids": {"1", "2", "3"},
		},
		URL: u,
	}
	r.AddCookie(&http.Cookie{
		Name:  "Token",
		Value: "foo-bar-andsoon",
	})

	Controller(w, r)

	fmt.Println(w.Result().Status)
	fmt.Println(w.Body.String())
}

自定义绑定逻辑

package main

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"reflect"
	"testing"
	"github.com/bdjimmy/gbind"
)

func TestRegisterBindFunc(t *testing.T) {
	g := gbind.NewGbind()
	g.RegisterBindFunc("simple", NewSimpleExecer)

	type Foo struct {
		Key string `gbind:"simple.key"`
	}
	f := &Foo{}
	_, err := g.Bind(context.WithValue(context.Background(), exprKey{}, "simple-k-d"), f, nil)
	if err != nil {
		t.Fatal(err)
	}
	fmt.Println(f.Key) // 输出: simple-k-d
}

type exprKey struct{}

func NewSimpleExecer(values [][]byte) (gbind.Execer, error) {
	n := len(values)
	if n != 2 {
		return nil, errors.New("syntax error: simple error")
	}
	switch {
	case bytes.Equal(values[1], []byte("key")):
		return &simpleKeyExecer{}, nil
	}
	return nil, fmt.Errorf("syntax error: not support simple %s", values[1])
}

type simpleKeyExecer struct{}

func (s *simpleKeyExecer) Exec(ctx context.Context, value reflect.Value, data interface{}, opt *gbind.DefaultOption) (context.Context, error) {
	err := gbind.TrySet(value, []string{ctx.Value(exprKey{}).(string)}, opt)
	return ctx, err
}

func (s *simpleKeyExecer) Name() string {
	return "simple.key"
}

自定义验证逻辑

package main

import (
	"testing"
	"github.com/bdjimmy/gbind"
	"github.com/go-playground/validator/v10"
)

func TestRegisterCustomValidation(t *testing.T) {
	g := gbind.NewGbind()

	g.RegisterCustomValidation("is-awesome", func(fl validator.FieldLevel) bool {
		return fl.Field().String() == "awesome"
	})

	type Foo struct {
		Appkey string `gbind:"http.query.appkey" validate:"is-awesome"`
	}
	f := &Foo{}
	req := NewReq().AddQueryParam("appkey", "awesome").R()
	_, err := g.BindWithValidate(context.Background(), f, req)
	if err != nil {
		t.Fatal(err)
	}
}

性能基准测试

  • HTTP query+form参数绑定性能比较:
BenchmarkBind/gin-query-form-8         612357      1937 ns/op     304 B/op      20 allocs/op
BenchmarkBind/gbind-query-form-8       6981271     171.3 ns/op    200 B/op      5 allocs/op
  • HTTP query+form+header参数绑定性能比较:
BenchmarkBind/gin-query-form-header-8   232152      5143 ns/op     736 B/op     53 allocs/op
BenchmarkBind/gbind-query-form-header-8 6673236    180.0 ns/op    232 B/op     5 allocs/op

支持的底层数据类型

  • 基本数据类型:

    • int、int8、int16、int32、int64
    • uint、uint8、uint16、uint32、uint64
    • float32、float64
    • bool
    • string
  • 其他数据类型:

    • 指针类型(包括多级指针)
    • 切片类型
    • 数组类型
    • time.Duration

更多关于golang数据绑定与验证插件库gbind的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang数据绑定与验证插件库gbind的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang数据绑定与验证插件库gbind使用指南

gbind是一个用于Golang的数据绑定和验证的轻量级库,它可以帮助开发者将请求数据(如JSON、表单等)绑定到结构体,并进行数据验证。

安装

go get github.com/gobind/gbind

基本使用

1. 数据绑定

首先定义一个结构体用于接收数据:

type User struct {
    Name     string `json:"name" form:"name"`
    Age      int    `json:"age" form:"age"`
    Email    string `json:"email" form:"email"`
    Password string `json:"password" form:"password"`
}

在HTTP处理器中使用gbind进行数据绑定:

import "github.com/gobind/gbind"

func CreateUser(w http.ResponseWriter, r *http.Request) {
    var user User
    
    // 绑定数据
    if err := gbind.Bind(r, &user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // 处理用户数据...
    fmt.Fprintf(w, "User created: %+v", user)
}

2. 数据验证

gbind支持使用标签进行数据验证:

type User struct {
    Name     string `json:"name" form:"name" validate:"required,min=3,max=50"`
    Age      int    `json:"age" form:"age" validate:"required,min=18,max=120"`
    Email    string `json:"email" form:"email" validate:"required,email"`
    Password string `json:"password" form:"password" validate:"required,min=8"`
}

在绑定后执行验证:

func CreateUser(w http.ResponseWriter, r *http.Request) {
    var user User
    
    // 绑定并验证数据
    if err := gbind.BindAndValidate(r, &user); err != nil {
        // 处理验证错误
        if verr, ok := err.(gbind.ValidationErrors); ok {
            for _, e := range verr {
                fmt.Printf("Field %s failed validation: %s\n", e.Field, e.Message)
            }
        }
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // 处理用户数据...
    fmt.Fprintf(w, "User created: %+v", user)
}

支持的验证规则

gbind支持以下常用验证规则:

  • required - 字段必须存在且不为零值
  • min=n - 最小长度/数值
  • max=n - 最大长度/数值
  • email - 必须是有效的电子邮件格式
  • eqfield=OtherField - 必须等于另一个字段的值
  • oneof=a b c - 值必须是给定列表中的一个
  • len=n - 长度必须等于n
  • numeric - 必须是数字
  • alpha - 只能包含字母字符
  • alphanum - 只能包含字母和数字字符

自定义验证器

你可以注册自定义验证器:

// 自定义验证函数
func isAdmin(field gbind.FieldLevel) bool {
    value := field.Field().String()
    return value == "admin"
}

func init() {
    // 注册自定义验证器
    gbind.RegisterValidation("isadmin", isAdmin)
}

// 在结构体中使用
type User struct {
    Username string `json:"username" validate:"isadmin"`
    // ...
}

处理不同内容类型

gbind自动根据Content-Type处理不同格式的数据:

  • application/json - 解析JSON数据
  • application/x-www-form-urlencoded - 解析表单数据
  • multipart/form-data - 解析多部分表单数据(包括文件上传)

高级用法

1. 仅绑定特定内容

// 只绑定JSON数据
if err := gbind.BindJSON(r, &user); err != nil {
    // 处理错误
}

// 只绑定表单数据
if err := gbind.BindForm(r, &user); err != nil {
    // 处理错误
}

2. 自定义错误消息

type User struct {
    Name string `json:"name" validate:"required" message:"Name is required"`
    Age  int    `json:"age" validate:"required,min=18" message:"Age must be at least 18"`
}

3. 嵌套结构体验证

type Address struct {
    Street string `json:"street" validate:"required"`
    City   string `json:"city" validate:"required"`
}

type User struct {
    Name    string  `json:"name" validate:"required"`
    Address Address `json:"address"`
}

性能考虑

gbind在设计时考虑了性能因素:

  1. 使用反射但缓存了反射结果
  2. 验证规则在第一次使用时编译并缓存
  3. 尽量减少内存分配

与其他库的比较

相比于其他验证库如go-playground/validator,gbind提供了:

  1. 更简洁的API
  2. 内置数据绑定功能
  3. 更友好的错误消息处理
  4. 更轻量的实现

总结

gbind是一个简单而强大的Golang数据绑定和验证库,它可以帮助开发者:

  1. 轻松地将请求数据绑定到结构体
  2. 使用声明式标签验证数据
  3. 自定义验证规则和错误消息
  4. 处理多种内容类型的数据

通过合理使用gbind,可以显著减少数据绑定和验证的样板代码,提高开发效率。

更多详细用法请参考官方文档:https://github.com/gobind/gbind

回到顶部