binding

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Jun 6, 2019 License: Apache-2.0 Imports: 15 Imported by: 0

README

binding GoDoc

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

Example

package binding_test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/bytedance/go-tagexpr/binding"
	"github.com/henrylee2cn/goutil/httpbody"
)

func Example() {
	type InfoRequest struct {
		Name          string   `api:"{path:'name'}"`
		Year          []int    `api:"{query:'year'}"`
		Email         *string  `api:"{body:'email'}{@:email($)}"`
		Friendly      bool     `api:"{body:'friendly'}"`
		Pie           float32  `api:"{body:'pie'}{required:true}"`
		Hobby         []string `api:"{body:'hobby'}"`
		BodyNotFound  *int     `api:"{body:'xxx'}"`
		Authorization string   `api:"{header:'Authorization'}{required:true}{@:$=='Basic 123456'}"`
		SessionID     string   `api:"{cookie:'sessionid'}{required:true}"`
		AutoBody      string
		AutoQuery     string
		AutoNotFound  *string
	}

	args := new(InfoRequest)
	binder := binding.New("api")
	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&AutoQuery=autoquery_test 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","email":"henrylee2cn@gmail.com","friendly":true,"hobby":["Coding","Mountain climbing"],"pie":3.1415926}
	// 0
	//
	// bind and validate result:
	// error: <nil>
	// args JSON string:
	// {
	// 	"Name": "henrylee2cn",
	// 	"Year": [
	// 		2018,
	// 		2019
	// 	],
	// 	"Email": "henrylee2cn@gmail.com",
	// 	"Friendly": true,
	// 	"Pie": 3.1415925,
	// 	"Hobby": [
	// 		"Coding",
	// 		"Mountain climbing"
	// 	],
	// 	"BodyNotFound": null,
	// 	"Authorization": "Basic 123456",
	// 	"SessionID": "987654",
	// 	"AutoBody": "autobody_test",
	// 	"AutoQuery": "autoquery_test",
	// 	"AutoNotFound": null
	// }
}
...

Position

The parameter position in HTTP request:

expression description
{path:'$name'} URL path parameter
{query:'$name'} URL query parameter
{body:'$name'} The field in body, support:
application/json,
application/x-www-form-urlencoded,
multipart/form-data
{header:'$name'} Header parameter
{cookie:'$name'} Cookie parameter

NOTE:

  • '$name' is variable placeholder
  • If '$name' is empty, use the name of field
  • If no position is tagged, use body first, followed by query
  • Expression {required:true} indicates that the parameter is required

Level

The level of handling tags:

level default description
OnlyFirst No Handle only the first level fields
FirstAndTagged Yes Handle the first level fields and all the tagged fields
Any No Handle any level fields

Documentation

Overview

Example
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/bytedance/go-tagexpr/binding"
	"github.com/henrylee2cn/goutil/httpbody"
)

func main() {
	type InfoRequest struct {
		Name          string   `api:"{path:'name'}"`
		Year          []int    `api:"{query:'year'}"`
		Email         *string  `api:"{body:'email'}{@:email($)}"`
		Friendly      bool     `api:"{body:'friendly'}"`
		Pie           float32  `api:"{body:'pie'}{required:true}"`
		Hobby         []string `api:"{body:'hobby'}"`
		BodyNotFound  *int     `api:"{body:'xxx'}"`
		Authorization string   `api:"{header:'Authorization'}{required:true}{@:$=='Basic 123456'}"`
		SessionID     string   `api:"{cookie:'sessionid'}{required:true}"`
		AutoBody      string
		AutoQuery     string
		AutoNotFound  *string
	}

	args := new(InfoRequest)
	binder := binding.New("api")
	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")
	cookies := []*http.Cookie{
		{Name: "sessionid", Value: "987654"},
	}
	req := newRequest("http://localhost/info/henrylee2cn?year=2018&year=2019&AutoQuery=autoquery_test", 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&AutoQuery=autoquery_test 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","email":"henrylee2cn@gmail.com","friendly":true,"hobby":["Coding","Mountain climbing"],"pie":3.1415926}
0

bind and validate result:
error: <nil>
args JSON string:
{
	"Name": "henrylee2cn",
	"Year": [
		2018,
		2019
	],
	"Email": "henrylee2cn@gmail.com",
	"Friendly": true,
	"Pie": 3.1415925,
	"Hobby": [
		"Coding",
		"Mountain climbing"
	],
	"BodyNotFound": null,
	"Authorization": "Basic 123456",
	"SessionID": "987654",
	"AutoBody": "autobody_test",
	"AutoQuery": "autoquery_test",
	"AutoNotFound": null
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Binding

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

Binding binding and verification tool for http request

func New

func New(tagName string) *Binding

New creates a binding tool. NOTE:

If tagName=='', `api` is used

func (*Binding) Bind

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

Bind binds the request parameters.

func (*Binding) BindAndValidate

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

BindAndValidate binds the request parameters and validates them if needed.

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) SetLevel

func (b *Binding) SetLevel(level Level) *Binding

SetLevel set the level of handling tags. NOTE:

default is First

func (*Binding) Validate

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

Validate validates whether the fields of v is valid.

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 Level

type Level uint8

Level the level of handling tags

const (
	// OnlyFirst handle only the first level fields
	OnlyFirst Level = iota
	// FirstAndTagged handle the first level fields and all the tagged fields
	FirstAndTagged
	// Any handle any level fields
	Any
)

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

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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