Documentation
¶
Overview ¶
Package bind contains model binding features to be used along *http.Request.
Binding functions ¶
All the functions of this package are binding functions, that parse the string data from the request and binds the result to a Go struct. Supported functions are:
- [URIParameters] - one or more URL parameters;
- [URIParameter] - one URL parameter;
- Body - body or forms (of any kind);
- Query - query parameters or GET forms;
- Header - one or more header fields;
- HeaderField - one header field;
- Request - optimized combination of [URIParameters], Body, Query and Header. Preferred for reading from multiple inputs.
If any of these functions fails to parse the request (for example, they couldn't bind a non-numeric string into an integer field), they return *Error, that contains a user-friendly message and can be used in the response as is.
Receiving files ¶
Body and Request support uploading of files from multipart form requests, with the only requirements being using the appropriate "file" tag and making targeted fields of type *mime/multipart.FileHeader (or its slice variant). Check the package-level example.
Validations ¶
The bind package is integrated with the github.com/libchaos/litchi/validate package. If a struct passed as type parameter for Request, [URIParameters], Body, Query or Header implements the github.com/libchaos/litchi/validate.Validatable interface with a pointer receiver, these binding functions validate the result and can return a validation error with a user-friendly message.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnsupportedContentType = errors.New("unsupported Content-Type")
Functions ¶
func Body ¶
Body binds the request's body into the fields of a struct of type T.
It checks the Content-Type header to select an appropriated parsing method:
- "application/json" for JSON parsing
- "application/xml" or "text/xml" for XML parsing
- "application/x-yaml" for YAML parsing
- "application/x-www-form-urlencoded" or "multipart/form-data" for form parsing
Tags from encoding packages, such as "json", "xml" and "yaml" tags, can be used appropriately. For form parsing, use the tag "form".
For files inside multipart forms, use the tag "file". Target fields should also be of type *mime/multipart.FileHeader or []*mime/multipart.FileHeader. The maximum number of bytes stored in memory is 32MB, while the rest is stored in temporary files.
If the Content-Type header is not set, Body defaults to JSON parsing. If it is not supported, it returns ErrUnsupportedContentType.
If *T implements validate.Validatable (with a pointer receiver), Body calls validate.Fields on the result and can return validate.Error.
If T is not a struct type, Body panics.
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "strings" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodPost, "/books", strings.NewReader(` {"name": "Percy Jackson", "publishYear": 2009} `)) r := req type RequestBody struct { Name string `json:"name"` PublishYear int `json:"publishYear"` } body, err := bind.Body[RequestBody](r) if err == nil { fmt.Println(body.Name) fmt.Println(body.PublishYear) } }
Output: Percy Jackson 2009
Example (Form) ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodGet, "/books", nil) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.URL.RawQuery = "publishYear=2009&name=Percy%20Jackson" r := req type RequestBody struct { Name string `form:"name"` PublishYear int `form:"publishYear"` } body, err := bind.Body[RequestBody](r) if err == nil { fmt.Println(body.Name) fmt.Println(body.PublishYear) } }
Output: Percy Jackson 2009
func Header ¶
Header binds the request's header into the fields of a struct of type T. Targeted fields should be exported and annotated with the tag "header" (case-insensitive). Otherwise, they are ignored.
If any field couldn't be bound, Header returns Error.
If *T implements validate.Validatable (with a pointer receiver), Header calls validate.Fields on the result and can return validate.Error.
If T is not a struct type, Header panics.
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodGet, "/books", nil) req.Header.Add("Content-Length", "150") req.Header.Add("Authorization", "Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH") r := req type Header struct { ContentLength uint `header:"Content-Length"` Authorization string `header:"Authorization"` } h, err := bind.Header[Header](r) if err == nil { fmt.Println(h.ContentLength) fmt.Println(h.Authorization) } }
Output: 150 Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH
func HeaderField ¶
HeaderField binds a field from the request's header into a value of type T. T can be either a primitive type or a time.Time.
HeaderField consider header as case-insensitive.
If the value can't be bound into T, HeaderField returns Error.
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodGet, "/books", nil) req.Header.Add("Content-Length", "150") req.Header.Add("Authorization", "Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH") r := req contentLength, err := bind.HeaderField[int](r, "Content-Length") if err == nil { fmt.Println(contentLength) } authorization, err := bind.HeaderField[string](r, "authorization") // case-insensitive if err == nil { fmt.Println(authorization) } }
Output: 150 Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH
func Query ¶
Query binds the request's query parameters into the fields of a struct of type T. Targeted fields should be exported and annotated with the tag "query". Otherwise, they are ignored.
If a field can't be bound, Query returns Error.
If *T implements validate.Validatable (with a pointer receiver), Query calls validate.Fields on the result and can return validate.Error.
If T is not a struct type, Query panics.
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodGet, "/books", nil) req.URL.RawQuery = "publish_year=2009&name=Percy%20Jackson" r := req type BookQuery struct { PublishYear uint `query:"publish_year"` Name string `query:"name"` } query, err := bind.Query[BookQuery](r) if err == nil { fmt.Println(query.PublishYear, query.Name) } }
Output: 2009 Percy Jackson
Example (Form) ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/libchaos/litchi/bind" ) func main() { req := httptest.NewRequest(http.MethodGet, "/books", nil) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.URL.RawQuery = "publish_year=2009&name=Percy%20Jackson" r := req type BookQuery struct { PublishYear uint `query:"publish_year"` Name string `query:"name"` } query, err := bind.Query[BookQuery](r) if err == nil { fmt.Println(query.PublishYear, query.Name) } }
Output: 2009 Percy Jackson
func Request ¶
Request binds the request's body, query, header and URI parameters into the fields of a struct of type T. Targeted fields should be exported and annotated with corresponding binding tags. Otherwise, they are ignored.
It's an optimized combination of the binding functions Body, Query, Header and [URIParameters], suitable when you need to read from multiple inputs of the request.
If a field can't be bound, Request returns Error.
If *T implements validate.Validatable (with a pointer receiver), Request calls validate.Fields on the result and can return validate.Error.
If T is not a struct type, Request panics.