apiware

package
v0.0.0-...-7c1bd55 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2017 License: Apache-2.0, Apache-2.0 Imports: 14 Imported by: 0

README

Apiware GoDoc

Apiware binds the specified parameters of the Golang net/http and fasthttp requests to the structure and verifies the validity of the parameter values.

It is suggested that you can use the struct as the Handler of the web framework, and use the middleware to quickly bind the request parameters, saving a lot of parameter type conversion and validity verification. At the same time through the struct tag, create swagger json configuration file, easy to create api document services.

Apiware将Go语言net/httpfasthttp请求的指定参数绑定到结构体,并验证参数值的合法性。 建议您可以使用结构体作为web框架的Handler,并用该中间件快速绑定请求参数,节省了大量参数类型转换与有效性验证的工作。同时还可以通过该结构体标签,创建swagger的json配置文件,轻松创建api文档服务。

Demo 示例

package main

import (
    "encoding/json"
    "github.com/henrylee2cn/faygo/apiware"
    // "mime/multipart"
    "net/http"
    "strings"
)

type TestApiware struct {
    Id           int         `param:"<in:path> <required> <desc:ID> <range: 1:2>"`
    Num          float32     `param:"<in:query> <name:n> <range: 0.1:10.19>"`
    Title        string      `param:"<in:query> <nonzero>"`
    Paragraph    []string    `param:"<in:query> <name:p> <len: 1:10> <regexp: ^[\\w]*$>"`
    Cookie       http.Cookie `param:"<in:cookie> <name:apiwareid>"`
    CookieString string      `param:"<in:cookie> <name:apiwareid>"`
    // Picture   multipart.FileHeader `param:"<in:formData> <name:pic> <maxmb:30>"`
}

var myApiware = apiware.New(pathdecoder, nil, nil)

var pattern = "/test/:id"

func pathdecoder(urlPath, pattern string) apiware.KV {
    idx := map[int]string{}
    for k, v := range strings.Split(pattern, "/") {
        if !strings.HasPrefix(v, ":") {
            continue
        }
        idx[k] = v[1:]
    }
    pathParams := make(map[string]string, len(idx))
    for k, v := range strings.Split(urlPath, "/") {
        name, ok := idx[k]
        if !ok {
            continue
        }
        pathParams[name] = v
    }
    return apiware.Map(pathParams)
}

func testHandler(resp http.ResponseWriter, req *http.Request) {
    // set cookies
    http.SetCookie(resp, &http.Cookie{
        Name:  "apiwareid",
        Value: "http_henrylee2cn",
    })

    // bind params
    params := new(TestApiware)
    err := myApiware.Bind(params, req, pattern)
    b, _ := json.MarshalIndent(params, "", " ")
    if err != nil {
        resp.WriteHeader(http.StatusBadRequest)
        resp.Write(append([]byte(err.Error()+"\n"), b...))
    } else {
        resp.WriteHeader(http.StatusOK)
        resp.Write(b)
    }
}

func main() {
    // Check whether `testHandler` meet the requirements of apiware, and register it
    err := myApiware.Register(new(TestApiware))
    if err != nil {
        panic(err)
    }

    // server
    http.HandleFunc("/test/0", testHandler)
    http.HandleFunc("/test/1", testHandler)
    http.HandleFunc("/test/1.1", testHandler)
    http.HandleFunc("/test/2", testHandler)
    http.HandleFunc("/test/3", testHandler)
    http.ListenAndServe(":8080", nil)
}

Struct&Tag 结构体及其标签

tag key required value desc
param in only one path (position of param) if required is unsetted, auto set it. e.g. url: "http://www.abc.com/a/{path}"
param in only one query (position of param) e.g. url: "http://www.abc.com/a?b={query}"
param in only one formData (position of param) e.g. "request body: a=123&b={formData}"
param in only one body (position of param) request body can be any content
param in only one header (position of param) request header info
param in only one cookie (position of param) request cookie info, support: http.Cookie,fasthttp.Cookie,string,[]byte
param name no (e.g.id) specify request param`s name
param required no request param is required
param desc no (e.g.id) request param description
param len no (e.g.3:6 3) length range of param's value
param range no (e.g.0:10) numerical range of param's value
param nonzero no param`s value can not be zero
param maxmb no (e.g.32) when request Content-Type is multipart/form-data, the max memory for body.(multi-param, whichever is greater)
param regexp no (e.g.^\\w+$) verify the value of the param with a regular expression(param value can not be null)
param err no (e.g.incorrect password format) the custom error for binding or validating

NOTES:

  • the binding object must be a struct pointer
  • in addition to *multipart.FileHeader, the binding struct's field can not be a pointer
  • regexp or param tag is only usable when param:"type(xxx)" is exist
  • if the param tag is not exist, anonymous field will be parsed
  • when the param's position(in) is formData and the field's type is multipart.FileHeader, the param receives file uploaded
  • if param's position(in) is cookie, field's type must be http.Cookie
  • param tags in(formData) and in(body) can not exist at the same time
  • there should not be more than one in(body) param tag

Field Types 结构体字段类型

base slice special
string []string [][]byte
byte []byte [][]uint8
uint8 []uint8 *multipart.FileHeader (only for formData param)
bool []bool []*multipart.FileHeader (only for formData param)
int []int http.Cookie (only for net/http's cookie param)
int8 []int8 fasthttp.Cookie (only for fasthttp's cookie param)
int16 []int16 struct (struct type only for body param or as an anonymous field to extend params)
int32 []int32
int64 []int64
uint8 []uint8
uint16 []uint16
uint32 []uint32
uint64 []uint64
float32 []float32
float64 []float64

Documentation

Overview

Package apiware provides a tools which can bind the http/fasthttp request params to the structure and validate.

Copyright 2016 HenryLee. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Param tag value description:

tag   |   key    | required |     value     |   desc
------|----------|----------|---------------|----------------------------------
param |    in    | only one |     path      | (position of param) if `required` is unsetted, auto set it. e.g. url: "http://www.abc.com/a/{path}"
param |    in    | only one |     query     | (position of param) e.g. url: "http://www.abc.com/a?b={query}"
param |    in    | only one |     formData  | (position of param) e.g. "request body: a=123&b={formData}"
param |    in    | only one |     body      | (position of param) request body can be any content
param |    in    | only one |     header    | (position of param) request header info
param |    in    | only one |     cookie    | (position of param) request cookie info, support: `*http.Cookie`,`http.Cookie`,`string`,`[]byte`
param |   name   |    no    |   (e.g.`id`)   | specify request param`s name
param | required |    no    |               | request param is required
param |   desc   |    no    |   (e.g.`id`)   | request param description
param |   len    |    no    | (e.g.`3:6` `3`) | length range of param's value
param |   range  |    no    |  (e.g.`0:10`)  | numerical range of param's value
param |  nonzero |    no    |               | param`s value can not be zero
param |   maxmb  |    no    |   (e.g.`32`)   | when request Content-Type is multipart/form-data, the max memory for body.(multi-param, whichever is greater)
param |  regexp  |    no    | (e.g.`^\\w+$`) | verify the value of the param with a regular expression(param value can not be null)
param |   err    |    no    |(e.g.`incorrect password format`)| the custom error for binding or validating

NOTES:
    1. the binding object must be a struct pointer
    2. in addition to `*multipart.FileHeader`, the binding struct's field can not be a pointer
    3. `regexp` or `param` tag is only usable when `param:"type(xxx)"` is exist
    4. if the `param` tag is not exist, anonymous field will be parsed
    5. when the param's position(`in`) is `formData` and the field's type is `*multipart.FileHeader`, `multipart.FileHeader`, `[]*multipart.FileHeader` or `[]multipart.FileHeader`, the param receives file uploaded
    6. if param's position(`in`) is `cookie`, field's type must be `*http.Cookie` or `http.Cookie`
    7. param tags `in(formData)` and `in(body)` can not exist at the same time
    8. there should not be more than one `in(body)` param tag

List of supported param value types:

base    |   slice    | special
--------|------------|-------------------------------------------------------
string  |  []string  | [][]byte
byte    |  []byte    | [][]uint8
uint8   |  []uint8   | *multipart.FileHeader (only for `formData` param)
bool    |  []bool    | []*multipart.FileHeader (only for `formData` param)
int     |  []int     | *http.Cookie (only for `net/http`'s `cookie` param)
int8    |  []int8    | http.Cookie (only for `net/http`'s `cookie` param)
int16   |  []int16   | struct (struct type only for `body` param or as an anonymous field to extend params)
int32   |  []int32   |
int64   |  []int64   |
uint8   |  []uint8   |
uint16  |  []uint16  |
uint32  |  []uint32  |
uint64  |  []uint64  |
float32 |  []float32 |
float64 |  []float64 |

Index

Constants

View Source
const (
	ValidationErrorValueNotSet = (1<<16 + iota)
	ValidationErrorValueTooSmall
	ValidationErrorValueTooBig
	ValidationErrorValueTooShort
	ValidationErrorValueTooLong
	ValidationErrorValueNotMatch
)

constant

View Source
const (
	TAG_PARAM        = "param"    // request param tag name
	TAG_IGNORE_PARAM = "-"        // ignore request param tag value
	KEY_IN           = "in"       // position of param
	KEY_NAME         = "name"     // specify request param`s name
	KEY_REQUIRED     = "required" // request param is required or not
	KEY_DESC         = "desc"     // request param description
	KEY_LEN          = "len"      // length range of param's value
	KEY_RANGE        = "range"    // numerical range of param's value
	KEY_NONZERO      = "nonzero"  // param`s value can not be zero
	KEY_REGEXP       = "regexp"   // verify the value of the param with a regular expression(param value can not be null)
	KEY_MAXMB        = "maxmb"    // when request Content-Type is multipart/form-data, the max memory for body.(multi-param, whichever is greater)
	KEY_ERR          = "err"      // the custom error for binding or validating

	MB = 1 << 20 // 1MB

)

some define

Variables

View Source
var (
	// TagInValues is values for tag 'in'
	TagInValues = map[string]bool{
		"path":     true,
		"query":    true,
		"formData": true,
		"body":     true,
		"header":   true,
		"cookie":   true,
	}
)

Functions

func Bind

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

Bind binds the net/http request params to the `structPointer` param and validate it. note: structPointer must be struct pointer.

func BindByName

func BindByName(
	paramsAPIName string,
	req *http.Request,
	pathParams KV,
) (
	interface{},
	error,
)

BindByName binds the net/http request params to a new struct and validate it.

func ConvertAssign

func ConvertAssign(dest reflect.Value, src ...string) (err error)

ConvertAssign type conversions for request params.

ConvertAssign copies to dest the value in src, converting it if possible. An error is returned if the copy would result in loss of information. dest should be a pointer type.

func NewValidationError

func NewValidationError(id int, field string) error

NewValidationError returns a new validation error with the specified id and text. The id's purpose is to distinguish different validation error types. Built-in validation error ids start at 65536, so you should keep your custom ids under that value.

func ParseTags

func ParseTags(tag string) map[string]string

ParseTags returns the key-value in the tag string. If the tag does not have the conventional format, the value returned by ParseTags is unspecified.

func Register

func Register(
	structPointer interface{},
	paramNameMapper ParamNameMapper,
	bodydecoder Bodydecoder,
) error

Register is similar to a `NewParamsAPI`, but only return error. Parse and store the struct object, requires a struct pointer, if `paramNameMapper` is nil, `paramNameMapper=toSnake`, if `bodydecoder` is nil, `bodydecoder=bodyJONS`,

func SetParamsAPI

func SetParamsAPI(paramsAPI *ParamsAPI)

SetParamsAPI caches `*ParamsAPI`

Types

type Apiware

type Apiware struct {
	ParamNameMapper
	Pathdecoder
	Bodydecoder
}

Apiware binds request paramters

func New

func New(pathdecoder Pathdecoder, bodydecoder Bodydecoder, paramNameMapper ParamNameMapper) *Apiware

New creates a new apiware engine. Parse and store the struct object, requires a struct pointer, if `paramNameMapper` is nil, `paramNameMapper=toSnake`, if `bodydecoder` is nil, `bodydecoder=bodyJONS`,

func (*Apiware) Bind

func (a *Apiware) Bind(
	structPointer interface{},
	req *http.Request,
	pattern string,
) error

Bind the net/http request params to the structure and validate. note: structPointer must be structure pointer.

func (*Apiware) Register

func (a *Apiware) Register(structPointers ...interface{}) error

Register checks whether structs meet the requirements of apiware, and register them. note: requires a structure pointer.

type Bodydecoder

type Bodydecoder func(dest reflect.Value, body []byte) error

Bodydecoder decodes params from request body.

type Error

type Error struct {
	Api    string `json:"api"`
	Param  string `json:"param"`
	Reason string `json:"reason"`
}

Error a formatted error type

func NewError

func NewError(api string, param string, reason string) *Error

NewError creates *Error

func (*Error) Error

func (e *Error) Error() string

Error implements error interface

type KV

type KV interface {
	Get(k string) (v string, found bool)
}

type Map

type Map map[string]string

func (Map) Get

func (m Map) Get(k string) (string, bool)

type Param

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

Param use the struct field to define a request parameter model

func (*Param) APIName

func (param *Param) APIName() string

APIName gets ParamsAPI name

func (*Param) Description

func (param *Param) Description() string

Description gets the description value for the param

func (*Param) In

func (param *Param) In() string

In get the type value for the param

func (*Param) IsFile

func (param *Param) IsFile() bool

IsFile tests if the param is type *multipart.FileHeader

func (*Param) IsRequired

func (param *Param) IsRequired() bool

IsRequired tests if the param is declared

func (*Param) Name

func (param *Param) Name() string

Name gets parameter field name

func (*Param) Raw

func (param *Param) Raw() interface{}

Raw gets the param's original value

type ParamNameMapper

type ParamNameMapper func(fieldName string) (paramName string)

ParamNameMapper maps param name from struct param name

type ParamsAPI

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

ParamsAPI defines a parameter model for an web api.

func GetParamsAPI

func GetParamsAPI(paramsAPIName string) (*ParamsAPI, error)

GetParamsAPI gets the `*ParamsAPI` object according to the type name

func NewParamsAPI

func NewParamsAPI(
	structPointer interface{},
	paramNameMapper ParamNameMapper,
	bodydecoder Bodydecoder,
) (
	*ParamsAPI,
	error,
)

NewParamsAPI parses and store the struct object, requires a struct pointer, if `paramNameMapper` is nil, `paramNameMapper=toSnake`, if `bodydecoder` is nil, `bodydecoder=bodyJONS`,

func (*ParamsAPI) BindAt

func (paramsAPI *ParamsAPI) BindAt(
	structPointer interface{},
	req *http.Request,
	pathParams KV,
) error

BindAt binds the net/http request params to a struct pointer and validate it. note: structPointer must be struct pointer.

func (*ParamsAPI) BindFields

func (paramsAPI *ParamsAPI) BindFields(
	fields []reflect.Value,
	req *http.Request,
	pathParams KV,
) (
	err error,
)

BindFields binds the net/http request params to a struct and validate it. Must ensure that the param `fields` matches `paramsAPI.params`.

func (*ParamsAPI) BindNew

func (paramsAPI *ParamsAPI) BindNew(
	req *http.Request,
	pathParams KV,
) (
	interface{},
	error,
)

BindNew binds the net/http request params to a struct pointer and validate it.

func (*ParamsAPI) MaxMemory

func (paramsAPI *ParamsAPI) MaxMemory() int64

MaxMemory gets maxMemory when request Content-Type is multipart/form-data, the max memory for body.

func (*ParamsAPI) Name

func (paramsAPI *ParamsAPI) Name() string

Name gets the name

func (*ParamsAPI) NewReceiver

func (paramsAPI *ParamsAPI) NewReceiver() (interface{}, []reflect.Value)

NewReceiver creates a new struct pointer and the field's values for its receive parameterste it.

func (*ParamsAPI) Number

func (paramsAPI *ParamsAPI) Number() int

Number returns the number of parameters to be bound

func (*ParamsAPI) Params

func (paramsAPI *ParamsAPI) Params() []*Param

Params gets the parameter information

func (*ParamsAPI) Raw

func (paramsAPI *ParamsAPI) Raw() interface{}

Raw returns the ParamsAPI's original value

func (*ParamsAPI) RawBind

func (paramsAPI *ParamsAPI) RawBind(
	req *http.Request,
	pathParams KV,
) (
	interface{},
	error,
)

RawBind binds the net/http request params to the original struct pointer and validate it.

func (*ParamsAPI) SetMaxMemory

func (paramsAPI *ParamsAPI) SetMaxMemory(maxMemory int64)

SetMaxMemory sets maxMemory for the request which Content-Type is multipart/form-data.

type Pathdecoder

type Pathdecoder func(urlPath, pattern string) (pathParams KV)

Pathdecoder parses path params function, return pathParams of KV type

type Schema

type Schema struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Schema is a collection of ParamsAPI

type ValidationError

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

Validation error type

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements error interface

func (*ValidationError) Field

func (e *ValidationError) Field() string

Field returns error field

func (*ValidationError) Kind

func (e *ValidationError) Kind() int

Kind returns error kind

Jump to

Keyboard shortcuts

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