binding

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2022 License: Apache-2.0 Imports: 24 Imported by: 0

README

binding GoDoc

A powerful HTTP request parameters binder that supports struct tag expression.

Example

func Example() {
	type InfoRequest struct {
		Name          string   `path:"name"`
		Year          []int    `query:"year"`
		Email         *string  `json:"email" vd:"email($)"`
		Friendly      bool     `json:"friendly"`
		Status        string   `json:"status" default:"single"`
		Pie           float32  `json:"pie,required"`
		Hobby         []string `json:",required"`
		BodyNotFound  *int     `json:"BodyNotFound"`
		Authorization string   `header:"Authorization,required" vd:"$=='Basic 123456'"`
		SessionID     string   `cookie:"sessionid,required"`
		AutoBody      string
		AutoNotFound  *string
		TimeRFC3339   time.Time `query:"t"`
	}

	args := new(InfoRequest)
	binder := binding.New(nil)
	err := binder.BindAndValidate(args, requestExample(), new(testPathParams))

	fmt.Println("bind and validate result:")

	fmt.Printf("error: %v\n", err)

	b, _ := json.MarshalIndent(args, "", "	")
	fmt.Printf("args JSON string:\n%s\n", b)

	// Output:
	// request:
	// POST /info/henrylee2cn?year=2018&year=2019&t=2019-09-04T18%3A04%3A08%2B08%3A00 HTTP/1.1
	// Host: localhost
	// User-Agent: Go-http-client/1.1
	// Transfer-Encoding: chunked
	// Authorization: Basic 123456
	// Content-Type: application/json;charset=utf-8
	// Cookie: sessionid=987654
	//
	// 83
	// {"AutoBody":"autobody_test","Hobby":["Coding","Mountain climbing"],"email":"henrylee2cn@gmail.com","friendly":true,"pie":3.1415926}
	// 0
	//
	// bind and validate result:
	// error: <nil>
	// args JSON string:
	// {
	// 	"Name": "henrylee2cn",
	// 	"Year": [
	// 		2018,
	// 		2019
	// 	],
	// 	"email": "henrylee2cn@gmail.com",
	// 	"friendly": true,
	// 	"status": "single",
	// 	"pie": 3.1415925,
	// 	"Hobby": [
	// 		"Coding",
	// 		"Mountain climbing"
	// 	],
	// 	"BodyNotFound": null,
	// 	"Authorization": "Basic 123456",
	// 	"SessionID": "987654",
	// 	"AutoBody": "autobody_test",
	// 	"AutoNotFound": null,
	// 	"TimeRFC3339": "2019-09-04T18:04:08+08:00"
	// }
}
...

Syntax

The parameter position in HTTP request:

expression renameable description
path:"$name" or path:"$name,required" Yes URL path parameter
query:"$name" or query:"$name,required" Yes URL query parameter
raw_body:"" or raw_body:"required" Yes The raw bytes of body
form:"$name" or form:"$name,required" Yes The field in body, support:
application/x-www-form-urlencoded,
multipart/form-data
protobuf:"...(raw syntax)" No The field in body, support:
application/x-protobuf
json:"$name" or json:"$name,required" No The field in body, support:
application/json
header:"$name" or header:"$name,required" Yes Header parameter
cookie:"$name" or cookie:"$name,required" Yes Cookie parameter
default:"$value" Yes Default parameter
vd:"...(tagexpr validator syntax)" Yes The tagexpr expression of validator

NOTE:

  • "$name" is variable placeholder
  • If "$name" is empty, use the name of field
  • If "$name" is -, omit the field
  • Expression required or req indicates that the parameter is required
  • default:"$value" defines the default value for fallback when no binding is successful
  • If no position is tagged, try bind parameters from the body when the request has body,
    otherwise try bind from the URL query
  • When there is unexportable and no tags, omit the field
  • When there are multiple tags, or exportable and no tags, the order in which to try to bind is:
    1. path
    2. form
    3. query
    4. cookie
    5. header
    6. protobuf
    7. json
    8. default

Type Unmarshalor

TimeRFC3339-binding function is registered by default.

Register your own binding function for the specified type, e.g.:

MustRegTypeUnmarshal(reflect.TypeOf(time.Time{}), func(v string, emptyAsZero bool) (reflect.Value, error) {
	if v == "" && emptyAsZero {
		return reflect.ValueOf(time.Time{}), nil
	}
	t, err := time.Parse(time.RFC3339, v)
	if err != nil {
		return reflect.Value{}, err
	}
	return reflect.ValueOf(t), nil
})

Documentation

Overview

Example
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/38888/go-tagexpr-new/goutil-loc/httpbody"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/38888/go-tagexpr-new/binding"
)

func main() {
	type InfoRequest struct {
		Name          string   `path:"name"`
		Year          []int    `query:"year"`
		Pages         []uint64 `query:"pages"`
		Email         *string  `json:"email" vd:"email($)"`
		Friendly      bool     `json:"friendly"`
		Pie           float32  `json:"pie,required"`
		Hobby         []string `json:",required"`
		BodyNotFound  *int     `json:"BodyNotFound"`
		Authorization string   `header:"Authorization,required" vd:"$=='Basic 123456'"`
		userIdHeader  string   `header:"x-user_ID,required"`
		SessionID     string   `cookie:"sessionid,required"`
		AutoBody      string
		AutoNotFound  *string
		TimeRFC3339   time.Time `query:"t"`
	}

	binding.MustRegTypeUnmarshal(reflect.TypeOf([]uint64{}), func(v string, emptyAsZero bool) (reflect.Value, error) {
		if v == "" && emptyAsZero {
			return reflect.ValueOf([]uint64{}), nil
		}

		ss := strings.Split(v, ",")
		t := make([]uint64, 0, len(ss))

		for _, s := range ss {
			i, err := strconv.ParseUint(s, 10, 64)
			if err != nil {
				return reflect.ValueOf([]uint64{}), err
			}
			t = append(t, i)
		}

		return reflect.ValueOf(t), nil
	})

	args := new(InfoRequest)
	binder := binding.New(nil)
	err := binder.BindAndValidate(args, requestExample(), new(testPathParams))

	fmt.Println("bind and validate result:")

	fmt.Printf("error: %v\n", err)

	b, _ := json.MarshalIndent(args, "", "	")
	fmt.Printf("args JSON string:\n%s\n", b)

}

func requestExample() *http.Request {
	contentType, bodyReader, _ := httpbody.NewJSONBody(map[string]interface{}{
		"email":    "henrylee2cn@gmail.com",
		"friendly": true,
		"pie":      3.1415926,
		"Hobby":    []string{"Coding", "Mountain climbing"},
		"AutoBody": "autobody_test",
	})
	header := make(http.Header)
	header.Add("Content-Type", contentType)
	header.Add("Authorization", "Basic 123456")
	header.Add("x-user_ID", "123456")
	cookies := []*http.Cookie{
		{Name: "sessionid", Value: "987654"},
	}
	req := newRequest("http://localhost/info/henrylee2cn?year=2018&year=2019&t=2019-09-04T18%3A04%3A08%2B08%3A00&pages=1,2,3", header, cookies, bodyReader)
	req.Method = "POST"
	var w bytes.Buffer
	req.Write(&w)
	fmt.Printf("request:\n%s", strings.Replace(w.String(), "\r\n", "\n", -1))

	bodyReader.(*bytes.Reader).Seek(0, 0)
	return req
}
Output:

request:
POST /info/henrylee2cn?year=2018&year=2019&t=2019-09-04T18%3A04%3A08%2B08%3A00&pages=1,2,3 HTTP/1.1
Host: localhost
User-Agent: Go-http-client/1.1
Transfer-Encoding: chunked
Authorization: Basic 123456
Content-Type: application/json;charset=utf-8
Cookie: sessionid=987654
X-User_id: 123456

83
{"AutoBody":"autobody_test","Hobby":["Coding","Mountain climbing"],"email":"henrylee2cn@gmail.com","friendly":true,"pie":3.1415926}
0

bind and validate result:
error: <nil>
args JSON string:
{
	"Name": "henrylee2cn",
	"Year": [
		2018,
		2019
	],
	"Pages": [
		1,
		2,
		3
	],
	"email": "henrylee2cn@gmail.com",
	"friendly": true,
	"pie": 3.1415925,
	"Hobby": [
		"Coding",
		"Mountain climbing"
	],
	"BodyNotFound": null,
	"Authorization": "Basic 123456",
	"SessionID": "987654",
	"AutoBody": "autobody_test",
	"AutoNotFound": null,
	"TimeRFC3339": "2019-09-04T18:04:08+08:00"
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Bind

func Bind(structPointer interface{}, req *http.Request, pathParams PathParams) error

Bind binds the request parameters.

func BindAndValidate

func BindAndValidate(structPointer interface{}, req *http.Request, pathParams PathParams) error

BindAndValidate binds the request parameters and validates them if needed.

func MustRegTypeUnmarshal

func MustRegTypeUnmarshal(t reflect.Type, fn func(v string, emptyAsZero bool) (reflect.Value, error))

MustRegTypeUnmarshal registers unmarshalor function of type. NOTE:

panic if exist error.

func RegTypeUnmarshal

func RegTypeUnmarshal(t reflect.Type, fn func(v string, emptyAsZero bool) (reflect.Value, error)) error

RegTypeUnmarshal registers unmarshalor function of type.

func ResetJSONUnmarshaler deprecated

func ResetJSONUnmarshaler(fn JSONUnmarshaler)

ResetJSONUnmarshaler reset the JSON Unmarshal function. NOTE: verifyingRequired is true if the required tag is supported.

Deprecated: please use: Default().ResetJSONUnmarshaler

func SetErrorFactory

func SetErrorFactory(bindErrFactory, validatingErrFactory func(failField, msg string) error)

SetErrorFactory customizes the factory of validation error. NOTE:

If errFactory==nil, the default is used

func SetLooseZeroMode

func SetLooseZeroMode(enable bool)

SetLooseZeroMode if set to true, the empty string request parameter is bound to the zero value of parameter. NOTE:

The default is false;
Suitable for these parameter types: query/header/cookie/form .

func Validate

func Validate(value interface{}) error

Validate validates whether the fields of value is valid.

Types

type Binding

type Binding struct {
	// contains filtered or unexported fields
}

Binding binding and verification tool for http request

func Default

func Default() *Binding

Default returns the default binding. NOTE:

path tag name is 'path';
query tag name is 'query';
header tag name is 'header';
cookie tag name is 'cookie';
raw_body tag name is 'raw_body';
form tag name is 'form';
validator tag name is 'vd';
protobuf tag name is 'protobuf';
json tag name is 'json';
LooseZeroMode is false.

func New

func New(config *Config) *Binding

New creates a binding tool. NOTE:

Use default tag name for config fields that are empty

func (*Binding) Bind

func (b *Binding) Bind(recvPointer interface{}, req *http.Request, pathParams PathParams) error

Bind binds the request parameters.

func (*Binding) BindAndValidate

func (b *Binding) BindAndValidate(recvPointer interface{}, req *http.Request, pathParams PathParams) error

BindAndValidate binds the request parameters and validates them if needed.

func (*Binding) IBind

func (b *Binding) IBind(recvPointer interface{}, req Request, pathParams PathParams) error

IBind binds the request parameters.

func (*Binding) IBindAndValidate

func (b *Binding) IBindAndValidate(recvPointer interface{}, req Request, pathParams PathParams) error

IBindAndValidate binds the request parameters and validates them if needed.

func (*Binding) ResetJSONUnmarshaler

func (b *Binding) ResetJSONUnmarshaler(fn JSONUnmarshaler)

func (*Binding) SetErrorFactory

func (b *Binding) SetErrorFactory(bindErrFactory, validatingErrFactory func(failField, msg string) error) *Binding

SetErrorFactory customizes the factory of validation error. NOTE:

If errFactory==nil, the default is used

func (*Binding) SetLooseZeroMode

func (b *Binding) SetLooseZeroMode(enable bool) *Binding

SetLooseZeroMode if set to true, the empty string request parameter is bound to the zero value of parameter. NOTE:

The default is false;
Suitable for these parameter types: query/header/cookie/form .

func (*Binding) Validate

func (b *Binding) Validate(value interface{}) error

Validate validates whether the fields of value is valid.

type Body

type Body struct {
	*bytes.Buffer
	// contains filtered or unexported fields
}

Body body copy

func GetBody

func GetBody(r *http.Request) (*Body, error)

GetBody get the body from http.Request

func (*Body) Bytes

func (b *Body) Bytes() []byte

Bytes returns all of the body bytes.

func (*Body) Close

func (b *Body) Close() error

Close close.

func (*Body) Len

func (b *Body) Len() int

Len returns all of the body length.

func (*Body) Reset

func (b *Body) Reset()

Reset zero offset.

type Config

type Config struct {
	// LooseZeroMode if set to true,
	// the empty string request parameter is bound to the zero value of parameter.
	// NOTE: Suitable for these parameter types: query/header/cookie/form .
	LooseZeroMode bool
	// PathParam use 'path' by default when empty
	PathParam string
	// Query use 'query' by default when empty
	Query string
	// Header use 'header' by default when empty
	Header string
	// Cookie use 'cookie' by default when empty
	Cookie string
	// RawBody use 'raw' by default when empty
	RawBody string
	// FormBody use 'form' by default when empty
	FormBody string
	// Validator use 'vd' by default when empty
	Validator string
	// contains filtered or unexported fields
}

Config the struct tag naming and so on

type Error

type Error struct {
	ErrType, FailField, Msg string
}

Error validate error

func (*Error) Error

func (e *Error) Error() string

Error implements error interface.

type JSONUnmarshaler

type JSONUnmarshaler func(data []byte, v interface{}) error

JSONUnmarshaler is the interface implemented by types that can unmarshal a JSON description of themselves.

type PathParams

type PathParams interface {
	// Get returns the value of the first parameter which key matches the given name.
	// If no matching parameter is found, an empty string is returned.
	Get(name string) (string, bool)
}

PathParams parameter acquisition interface on the URL path

type Request

type Request interface {
	GetMethod() string
	GetQuery() url.Values
	GetContentType() string
	GetHeader() http.Header
	GetCookies() []*http.Cookie
	GetBody() ([]byte, error)
	GetPostForm() (url.Values, error)
	GetForm() (url.Values, error)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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