Documentation ¶
Overview ¶
Package request implements simple decoding of http request - url path, queries, headers and body - into golang struct for easier consumption, resulting in less code boilerplate.
Implementation is based on OpenAPI 3 specification https://swagger.io/docs/specification/about/.
func (r *http.Request, w *http.Response) { var req struct { // path - requires Decoder.Path.Get to get value of path parameter Id `path:"id"` // query params ExplodedIds []int `query:"id"` // ?id=1&id=2&id=3 ImplodedIds []int `query:"ids,imploded"` // ?ids=1,2,3 Search string // ?search=foobar // body Client Client `body:"json"` } if err := request.Decode(r, &req); err != nil { // ... } }
Index ¶
Examples ¶
Constants ¶
const ( QueryDelimiterPipe = "|" QueryDelimiterSpace = " " QueryDelimiterComma = "," )
List of supported delimiters.
const ( QueryStyleForm = "form" // ?id=3,4,5 QueryStyleSpace = "space" // ?id=3%204%205 QueryStylePipe = "pipe" // ?id=3|4|5 QueryStyleDeep = "deep" // ?id[role]=admin&id[firstName]=Alex )
List of supported serialization styles.
Variables ¶
This section is empty.
Functions ¶
func Decode ¶
Decode decodes http request into golang struct using defaults of OpenAPI 3 specification.
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "strings" "go.expect.digital/request" ) func main() { r := httptest.NewRequest( http.MethodPost, "/?filterType=pending,approved&clientId=4&filterClientids=1|2|3", strings.NewReader(`{"id":1}`), ) var req struct { // query params FilterType []string `query:"filterType,imploded"` ClientId int FilterClientIds []int `query:",pipe,imploded"` // body Client struct { Id int } `body:"json"` } _ = request.Decode(r, &req) fmt.Printf("%+v\n", req) }
Output: {FilterType:[pending approved] ClientId:4 FilterClientIds:[1 2 3] Client:{Id:1}}
Types ¶
type Decoder ¶
func NewDecoder ¶
func NewDecoder() Decoder
func (Decoder) Decode ¶
Decode decodes http request into golang struct.
Decoding of query params follows specification of https://swagger.io/docs/specification/serialization/#query.
// required - decoding returns error if query param is not present var req struct { Name string `query:",required"` } // default - ?id=1&id=2&id=3 var req struct { Id []int // case insensitive match of field name and query parameter } // comma delimited - ?id=1,2,3 var req struct { Id []int `query:",form"` // implicitly imploded Ids []int `query:"id,imploded` // form by default } // pipe delimited - ?id=1|2|3 var req struct { Id []int `query:",pipe" // implicitly imploded } // space delimited - ?id=1%202%203 var req struct { Id []int `query:",space"` // implicitly imploded } // set different name - ?id=1,2,3 var req struct { FilterClientIds []int `query:"id,form"` // implicitly imploded }
Use encoding.TextUnmarshaler to implement custom decoding.
Decoding of request headers is NOT yet implemented.
Decoding of request body is simple - it uses either json or xml unmarshaller:
type Entity struct { Id int } // If no field tag value specified, "accept" request header is used to determine decoding. Uses json by default. var req struct { Entity `body:""` } // Always use json umarshalling, ignore "accept" request header: var req struct { Entity `body:"json"` } // Always use xml unmarshalling, ignore "accept" request header: var req struct { Entity `body:"xml"` }
Example ¶
package main import ( "fmt" "net/http" "net/http/httptest" "go.expect.digital/request" ) func main() { r := httptest.NewRequest(http.MethodPost, "/?ids=1,2,3", nil) var req struct { Ids []int } dec := request.NewDecoder() // set query values imploded "?ids=1,2,3" by default dec.Query.Exploded = false _ = dec.Decode(r, &req) fmt.Printf("%+v\n", req) }
Output: {Ids:[1 2 3]}