Documentation ¶
Overview ¶
Package inreq parses http requests to structs.
Index ¶
- Constants
- Variables
- func CustomDecode(r *http.Request, data any, options ...AnyOption) error
- func CustomDecodeType[T any](r *http.Request, options ...AnyTypeOption) (T, error)
- func Decode(r *http.Request, data any, options ...AnyOption) error
- func DecodeType[T any](r *http.Request, options ...AnyTypeOption) (T, error)
- type AnyOption
- type AnyTypeOption
- type BodyDecoder
- type CoerceError
- type DecodeContext
- type DecodeOperation
- type DecodeOperationBody
- type DecodeOperationForm
- type DecodeOperationHeader
- type DecodeOperationPath
- type DecodeOperationQuery
- type DecodeOption
- type Decoder
- type DefaultAndDecodeOption
- type DefaultAndTypeDefaultDecodeOption
- type DefaultAndTypeDefaultOption
- func WithBodyDecoder(bodyDecoder BodyDecoder) DefaultAndTypeDefaultOption
- func WithDecodeOperation(name string, operation DecodeOperation) DefaultAndTypeDefaultOption
- func WithDefaultDecodeOperations() DefaultAndTypeDefaultOption
- func WithDefaultMapTags(dataForType any, tags MapTags) DefaultAndTypeDefaultOption
- func WithDefaultMapTagsType(typ reflect.Type, tags MapTags) DefaultAndTypeDefaultOption
- func WithDefaultRequired(defaultRequired bool) DefaultAndTypeDefaultOption
- func WithFieldNameMapper(fieldNameMapper FieldNameMapper) DefaultAndTypeDefaultOption
- func WithPathValue(pathValue PathValue) DefaultAndTypeDefaultOption
- func WithResolver(resolver Resolver) DefaultAndTypeDefaultOption
- func WithSliceSplitSeparator(sep string) DefaultAndTypeDefaultOption
- func WithStructInfoCache(cache bool) DefaultAndTypeDefaultOption
- func WithTagName(tagName string) DefaultAndTypeDefaultOption
- type DefaultOption
- type FieldNameMapper
- type FullOption
- type InvalidDecodeError
- type MapTags
- type OperationNotSupportedError
- type PathValue
- type PathValueFunc
- type RequiredError
- type Resolver
- type StructOption
- type Tag
- type TypeDecodeOption
- type TypeDecoder
- type TypeDefaultAndDecodeOption
- type TypeDefaultAndTypeDecodeOption
- type TypeDefaultOption
- type ValuesNotUsedError
Examples ¶
Constants ¶
const ( OperationIgnore string = instruct.OperationIgnore OperationRecurse = instruct.OperationRecurse )
const ( OperationQuery string = "query" OperationPath = "path" OperationHeader = "header" OperationForm = "form" OperationBody = "body" )
Default operations.
const (
DefaultTagName = "inreq"
)
const StructOptionMapTag = instruct.StructOptionMapTag
StructOptionMapTag corresponds to StructOption in a MapTags.
Variables ¶
var ( ErrCoerceInvalid = types.ErrCoerceInvalid ErrCoerceOverflow = types.ErrCoerceOverflow ErrCoerceUnsupported = types.ErrCoerceUnsupported ErrCoerceUnknown = types.ErrCoerceUnknown )
var IgnoreDecodeValue = instruct.IgnoreDecodeValue
IgnoreDecodeValue can be returned from [DecodeOperation.Decode] to signal that the value should not be set on the struct field. This is used for example in the "body" decoder.
Functions ¶
func CustomDecode ¶
CustomDecode decodes the http request to the struct passed in "data" using NewCustomDecoder. Any map tags set using WithMapTags will be considered as "default" map tags. (see WithDefaultMapTags for details).
func CustomDecodeType ¶
func CustomDecodeType[T any](r *http.Request, options ...AnyTypeOption) (T, error)
CustomDecodeType decodes the http request to the struct passed in "data" using NewCustomDecoder. Any map tags set using WithMapTags will be considered as "default" map tags. (see WithDefaultMapTags for details).
func Decode ¶
Decode decodes the http request to the struct passed in "data" using NewDecoder. Any map tags set using WithMapTags will be considered as "default" map tags. (see WithDefaultMapTags for details).
Example ¶
package main import ( "fmt" "net/http" "strings" "github.com/rrgmc/inreq" ) type InputBody struct { DeviceID string `json:"device_id"` Name string `json:"name"` } type Input struct { AuthToken string `inreq:"header,name=X-Auth-Token"` DeviceID string `inreq:"path"` WithDetails bool `inreq:"query,name=with_details"` Page int `inreq:"query"` Body InputBody `inreq:"body"` FormDeviceName string `inreq:"form,name=devicename"` } func main() { r, err := http.NewRequest(http.MethodPost, "/device/12345?with_details=true&page=2", strings.NewReader(`{"device_id":"12345","name":"Device for testing"}`)) if err != nil { panic(err) } err = r.ParseForm() if err != nil { panic(err) } r.Header.Add("Content-Type", "application/json") r.Header.Add("X-Auth-Token", "auth-token-value") r.Form.Add("devicename", "form-device-name") data := &Input{} err = inreq.Decode(r, data, // usually this will be a framework-specific implementation, like "github.com/rrgmc/inreq-path/gorillamux". inreq.WithPathValue(inreq.PathValueFunc(func(r *http.Request, name string) (found bool, value any, err error) { if name == "deviceid" { return true, "12345", err } return false, nil, nil }))) if err != nil { panic(err) } fmt.Printf("Auth Token: %s\n", data.AuthToken) fmt.Printf("Device ID: %s\n", data.DeviceID) fmt.Printf("With details: %t\n", data.WithDetails) fmt.Printf("Page: %d\n", data.Page) fmt.Printf("Body Device ID: %s\n", data.Body.DeviceID) fmt.Printf("Body Name: %s\n", data.Body.Name) fmt.Printf("Form Device Name: %s\n", data.FormDeviceName) }
Output: Auth Token: auth-token-value Device ID: 12345 With details: true Page: 2 Body Device ID: 12345 Body Name: Device for testing Form Device Name: form-device-name
func DecodeType ¶
func DecodeType[T any](r *http.Request, options ...AnyTypeOption) (T, error)
DecodeType decodes the http request to the struct passed in "data" using NewDecoder. Any map tags set using WithMapTags will be considered as "default" map tags. (see WithDefaultMapTags for details).
Example ¶
package main import ( "fmt" "net/http" "strings" "github.com/rrgmc/inreq" ) type InputTypeBody struct { DeviceID string `json:"device_id"` Name string `json:"name"` } type InputType struct { AuthToken string `inreq:"header,name=X-Auth-Token"` DeviceID string `inreq:"path"` WithDetails bool `inreq:"query,name=with_details"` Page int `inreq:"query"` Body InputTypeBody `inreq:"body"` FormDeviceName string `inreq:"form,name=devicename"` } func main() { r, err := http.NewRequest(http.MethodPost, "/device/12345?with_details=true&page=2", strings.NewReader(`{"device_id":"12345","name":"Device for testing"}`)) if err != nil { panic(err) } err = r.ParseForm() if err != nil { panic(err) } r.Header.Add("Content-Type", "application/json") r.Header.Add("X-Auth-Token", "auth-token-value") r.Form.Add("devicename", "form-device-name") data, err := inreq.DecodeType[InputType](r, // usually this will be a framework-specific implementation, like "github.com/rrgmc/inreq-path/gorillamux". inreq.WithPathValue(inreq.PathValueFunc(func(r *http.Request, name string) (found bool, value any, err error) { if name == "deviceid" { return true, "12345", err } return false, nil, nil }))) if err != nil { panic(err) } fmt.Printf("Auth Token: %s\n", data.AuthToken) fmt.Printf("Device ID: %s\n", data.DeviceID) fmt.Printf("With details: %t\n", data.WithDetails) fmt.Printf("Page: %d\n", data.Page) fmt.Printf("Body Device ID: %s\n", data.Body.DeviceID) fmt.Printf("Body Name: %s\n", data.Body.Name) fmt.Printf("Form Device Name: %s\n", data.FormDeviceName) }
Output: Auth Token: auth-token-value Device ID: 12345 With details: true Page: 2 Body Device ID: 12345 Body Name: Device for testing Form Device Name: form-device-name
Types ¶
type AnyTypeOption ¶
type AnyTypeOption = options.AnyTypeOption[*http.Request, DecodeContext]
type BodyDecoder ¶
type BodyDecoder interface { // Unmarshal should unmarshal r.Body into data. If r.Body is read, "ctx.DecodedBody()" MUST be called // even if there are read errors. Unmarshal(ctx DecodeContext, typeParam string, r *http.Request, data any) (bool, any, error) }
BodyDecoder should unmarshal the body into "data". The default one supports JSON and XML.
func NewDefaultBodyDecoder ¶
func NewDefaultBodyDecoder() BodyDecoder
type CoerceError ¶
type CoerceError = types.CoerceError
type DecodeContext ¶
type DecodeContext interface { instruct.DecodeContext // PathValue is the function used to extract the path from the request. PathValue() PathValue // BodyDecoder is the interface used to parse body data into structs. BodyDecoder() BodyDecoder // IsBodyDecoded returns whether the body was already decoded. IsBodyDecoded() bool // DecodedBody signals that the body was decoded. DecodedBody() // SliceSplitSeparator returns the string used for string-to-array conversions. The default is ",". SliceSplitSeparator() string // AllowReadBody returns whether the user gave permission to read the request body. AllowReadBody() bool // EnsureAllQueryUsed returns whether to check if all query parameters were used. EnsureAllQueryUsed() bool // EnsureAllFormUsed returns whether to check if all form parameters were used. EnsureAllFormUsed() bool }
DecodeContext is the context sent to DecodeOperation.
type DecodeOperation ¶
type DecodeOperation = instruct.DecodeOperation[*http.Request, DecodeContext]
DecodeOperation is the interface for the http request-to-struct decoders.
type DecodeOperationBody ¶
type DecodeOperationBody struct { }
DecodeOperationBody is a DecodeOperation that reads values from the request body.
type DecodeOperationForm ¶
type DecodeOperationForm struct { }
DecodeOperationForm is a DecodeOperation that gets values from HTTP forms.
func (*DecodeOperationForm) Validate ¶
func (d *DecodeOperationForm) Validate(ctx DecodeContext, r *http.Request) error
type DecodeOperationHeader ¶
type DecodeOperationHeader struct { }
DecodeOperationHeader is a DecodeOperation that gets values from HTTP headers.
type DecodeOperationPath ¶
type DecodeOperationPath struct { }
DecodeOperationPath is a DecodeOperation that gets values from HTTP paths (or routes). This is always framework-specific.
type DecodeOperationQuery ¶
type DecodeOperationQuery struct { }
DecodeOperationQuery is a DecodeOperation that gets values from HTTP query parameters.
func (*DecodeOperationQuery) Validate ¶
func (d *DecodeOperationQuery) Validate(ctx DecodeContext, r *http.Request) error
type DecodeOption ¶
type DecodeOption = options.DecodeOption[*http.Request, DecodeContext, decodeOptions]
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder decodes http requests to structs.
func NewCustomDecoder ¶
func NewCustomDecoder(options ...DefaultOption) *Decoder
NewCustomDecoder creates a Decoder instance without any decode operations. At least one must be added for decoding to work.
func NewDecoder ¶
func NewDecoder(options ...DefaultOption) *Decoder
NewDecoder creates a Decoder instance with the default decode operations (query, path, header, form, body).
Example ¶
package main import ( "fmt" "net/http" "strings" "github.com/rrgmc/inreq" ) type InputDecoderBody struct { DeviceID string `json:"device_id"` Name string `json:"name"` } type InputDecoder struct { AuthToken string `inreq:"header,name=X-Auth-Token"` DeviceID string `inreq:"path"` WithDetails bool `inreq:"query,name=with_details"` Page int `inreq:"query"` Body InputDecoderBody `inreq:"body"` FormDeviceName string `inreq:"form,name=devicename"` } func main() { r, err := http.NewRequest(http.MethodPost, "/device/12345?with_details=true&page=2", strings.NewReader(`{"device_id":"12345","name":"Device for testing"}`)) if err != nil { panic(err) } err = r.ParseForm() if err != nil { panic(err) } r.Header.Add("Content-Type", "application/json") r.Header.Add("X-Auth-Token", "auth-token-value") r.Form.Add("devicename", "form-device-name") data := &Input{} decoder := inreq.NewDecoder( // usually this will be a framework-specific implementation, like "github.com/rrgmc/inreq-path/gorillamux". inreq.WithPathValue(inreq.PathValueFunc(func(r *http.Request, name string) (found bool, value any, err error) { if name == "deviceid" { return true, "12345", err } return false, nil, nil })), ) err = decoder.Decode(r, data) if err != nil { panic(err) } fmt.Printf("Auth Token: %s\n", data.AuthToken) fmt.Printf("Device ID: %s\n", data.DeviceID) fmt.Printf("With details: %t\n", data.WithDetails) fmt.Printf("Page: %d\n", data.Page) fmt.Printf("Body Device ID: %s\n", data.Body.DeviceID) fmt.Printf("Body Name: %s\n", data.Body.Name) fmt.Printf("Form Device Name: %s\n", data.FormDeviceName) }
Output: Auth Token: auth-token-value Device ID: 12345 With details: true Page: 2 Body Device ID: 12345 Body Name: Device for testing Form Device Name: form-device-name
type DefaultAndDecodeOption ¶
type DefaultAndDecodeOption = options.DefaultAndDecodeOption[*http.Request, DecodeContext, defaultOptions, decodeOptions]
type DefaultAndTypeDefaultDecodeOption ¶
type DefaultAndTypeDefaultDecodeOption = options.DefaultAndTypeDefaultDecodeOption[*http.Request, DecodeContext, decodeOptions, decodeOptions]
type DefaultAndTypeDefaultOption ¶
type DefaultAndTypeDefaultOption = options.DefaultAndTypeDefaultOption[*http.Request, DecodeContext, defaultOptions, typeDefaultOptions]
func WithBodyDecoder ¶
func WithBodyDecoder(bodyDecoder BodyDecoder) DefaultAndTypeDefaultOption
WithBodyDecoder sets the interface used to parse body data into structs.
func WithDecodeOperation ¶
func WithDecodeOperation(name string, operation DecodeOperation) DefaultAndTypeDefaultOption
WithDecodeOperation adds a decode operation.
func WithDefaultDecodeOperations ¶
func WithDefaultDecodeOperations() DefaultAndTypeDefaultOption
WithDefaultDecodeOperations adds the default operations (query, path, header, form and body). If the non-"Custom" calls are used, this option is added by default.
func WithDefaultMapTags ¶
func WithDefaultMapTags(dataForType any, tags MapTags) DefaultAndTypeDefaultOption
WithDefaultMapTags adds a "default" MapTags. The default one is checked alongside the tags, so the check for unused fields takes both in account. Passing a struct without any struct tags and using WithMapTags will result in "field configuration not found" errors (except in free-standing functions like Decode, CustomDecode, DecodeType and CustomDecodeType.
func WithDefaultMapTagsType ¶
func WithDefaultMapTagsType(typ reflect.Type, tags MapTags) DefaultAndTypeDefaultOption
WithDefaultMapTagsType is the same as WithDefaultMapTags using a reflect.Type.
func WithDefaultRequired ¶
func WithDefaultRequired(defaultRequired bool) DefaultAndTypeDefaultOption
WithDefaultRequired sets whether the default for fields should be "required" or "not required"
func WithFieldNameMapper ¶
func WithFieldNameMapper(fieldNameMapper FieldNameMapper) DefaultAndTypeDefaultOption
WithFieldNameMapper sets the field name mapper. Default one uses strings.ToLower.
func WithPathValue ¶
func WithPathValue(pathValue PathValue) DefaultAndTypeDefaultOption
WithPathValue sets the function used to extract the path from the request.
func WithResolver ¶
func WithResolver(resolver Resolver) DefaultAndTypeDefaultOption
WithResolver sets the decode Resolver.
func WithSliceSplitSeparator ¶
func WithSliceSplitSeparator(sep string) DefaultAndTypeDefaultOption
WithSliceSplitSeparator sets the string to be used as separator on string-to-array conversion. Default is ",".
func WithStructInfoCache ¶
func WithStructInfoCache(cache bool) DefaultAndTypeDefaultOption
WithStructInfoCache sets whether to cache info for structs on parse. Default is false.
func WithTagName ¶
func WithTagName(tagName string) DefaultAndTypeDefaultOption
WithTagName sets the tag name to check on structs. The default is "inreq".
type DefaultOption ¶
type DefaultOption = options.DefaultOption[*http.Request, DecodeContext, defaultOptions]
type FieldNameMapper ¶
type FieldNameMapper = instruct.FieldNameMapper
FieldNameMapper maps a struct field name to the header/query/form field name. The default one uses strings.ToLower.
type FullOption ¶
type FullOption = options.FullOption[*http.Request, DecodeContext, defaultOptions, typeDefaultOptions, decodeOptions, decodeOptions]
func WithAllowReadBody ¶
func WithAllowReadBody(allowReadBody bool) FullOption
WithAllowReadBody sets whether operations are allowed to read the request body. Default is false.
func WithEnsureAllFormUsed ¶
func WithEnsureAllFormUsed(ensureAllFormUsed bool) FullOption
WithEnsureAllFormUsed sets whether to check if all form parameters were used.
func WithEnsureAllQueryUsed ¶
func WithEnsureAllQueryUsed(ensureAllQueryUsed bool) FullOption
WithEnsureAllQueryUsed sets whether to check if all query parameters were used.
type InvalidDecodeError ¶
type InvalidDecodeError = types.InvalidDecodeError
type OperationNotSupportedError ¶
type OperationNotSupportedError = types.OperationNotSupportedError
type PathValue ¶
type PathValue interface {
GetRequestPath(r *http.Request, name string) (found bool, value any, err error)
}
PathValue is used by the "path" operation to extract the path from the request. Usually this is stored in the context by libraries like "gorilla/mux".
type PathValueFunc ¶
func (PathValueFunc) GetRequestPath ¶
type RequiredError ¶
type RequiredError = types.RequiredError
type StructOption ¶
type StructOption = instruct.StructOption
StructOption can be used as a struct field to give options to the struct itself.
type TypeDecodeOption ¶
type TypeDecodeOption = options.TypeDecodeOption[*http.Request, DecodeContext, decodeOptions]
type TypeDecoder ¶
type TypeDecoder[T any] struct { // contains filtered or unexported fields }
TypeDecoder decodes http requests to structs.
func NewCustomTypeDecoder ¶
func NewCustomTypeDecoder[T any](options ...TypeDefaultOption) *TypeDecoder[T]
NewCustomTypeDecoder creates a Decoder instance without any decode operations. At least one must be added for decoding to work.
func NewTypeDecoder ¶
func NewTypeDecoder[T any](options ...TypeDefaultOption) *TypeDecoder[T]
NewTypeDecoder creates a Decoder instance with the default decode operations (query, path, header, form, body).
Example ¶
package main import ( "fmt" "net/http" "strings" "github.com/rrgmc/inreq" ) type InputTypeDecoderBody struct { DeviceID string `json:"device_id"` Name string `json:"name"` } type InputTypeDecoder struct { AuthToken string `inreq:"header,name=X-Auth-Token"` DeviceID string `inreq:"path"` WithDetails bool `inreq:"query,name=with_details"` Page int `inreq:"query"` Body InputTypeDecoderBody `inreq:"body"` FormDeviceName string `inreq:"form,name=devicename"` } func main() { r, err := http.NewRequest(http.MethodPost, "/device/12345?with_details=true&page=2", strings.NewReader(`{"device_id":"12345","name":"Device for testing"}`)) if err != nil { panic(err) } err = r.ParseForm() if err != nil { panic(err) } r.Header.Add("Content-Type", "application/json") r.Header.Add("X-Auth-Token", "auth-token-value") r.Form.Add("devicename", "form-device-name") decoder := inreq.NewTypeDecoder[InputTypeDecoder]( // usually this will be a framework-specific implementation, like "github.com/rrgmc/inreq-path/gorillamux". inreq.WithPathValue(inreq.PathValueFunc(func(r *http.Request, name string) (found bool, value any, err error) { if name == "deviceid" { return true, "12345", err } return false, nil, nil }))) data, err := decoder.Decode(r) if err != nil { panic(err) } fmt.Printf("Auth Token: %s\n", data.AuthToken) fmt.Printf("Device ID: %s\n", data.DeviceID) fmt.Printf("With details: %t\n", data.WithDetails) fmt.Printf("Page: %d\n", data.Page) fmt.Printf("Body Device ID: %s\n", data.Body.DeviceID) fmt.Printf("Body Name: %s\n", data.Body.Name) fmt.Printf("Form Device Name: %s\n", data.FormDeviceName) }
Output: Auth Token: auth-token-value Device ID: 12345 With details: true Page: 2 Body Device ID: 12345 Body Name: Device for testing Form Device Name: form-device-name
func (*TypeDecoder[T]) Decode ¶
func (d *TypeDecoder[T]) Decode(r *http.Request, options ...TypeDecodeOption) (T, error)
Decode decodes the http request to the struct passed in "data".
type TypeDefaultAndDecodeOption ¶
type TypeDefaultAndDecodeOption = options.TypeDefaultAndDecodeOption[*http.Request, DecodeContext, typeDefaultOptions, decodeOptions]
func WithMapTags ¶
func WithMapTags(tags MapTags) TypeDefaultAndDecodeOption
WithMapTags sets decode-operation-specific MapTags. These override the default cached struct information but don't change the original one. This should be used to override configurations on each call.
type TypeDefaultAndTypeDecodeOption ¶
type TypeDefaultAndTypeDecodeOption = options.TypeDefaultAndTypeDecodeOption[*http.Request, DecodeContext, typeDefaultOptions, decodeOptions]
type TypeDefaultOption ¶
type TypeDefaultOption = options.TypeDefaultOption[*http.Request, DecodeContext, typeDefaultOptions]
type ValuesNotUsedError ¶
type ValuesNotUsedError = types.ValuesNotUsedError