Documentation ¶
Overview ¶
Package chain aids the composition of Handler wrapper chains that carry request-scoped data.
Review the test file for examples covering chain manipulation, and a way to pass data to detached scopes (for common use cases race conditions will not be encountered, but caution is warranted). Benchmarks are available showing a negligible increase in processing time and memory consumption, and no increase in memory allocations compared to nesting functions without an aid.
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "net/http/httptest" "github.com/codemodus/chain" "golang.org/x/net/context" ) var ( bTxt0 = "0" bTxt1 = "1" bTxtA = "A" bTxtEnd = "_END_" ) func main() { ctx := context.Background() // Add common data to the context. // Each wrapper writes either "0", "1", or "A" to the response body before // and after ServeHTTPContext() is called. // ctxHandler writes "_END_" to the response body and returns. ch00 := chain.New(ctxHandlerWrapper0, ctxHandlerWrapper0).SetContext(ctx) ch00A1 := ch00.Append(chain.Convert(httpHandlerWrapperA), ctxHandlerWrapper1) ch100A1 := chain.New(ctxHandlerWrapper1).SetContext(ctx) ch100A1 = ch100A1.Merge(ch00A1) mux := http.NewServeMux() mux.Handle("/path_implies_body/00_End", ch00.EndFn(ctxHandler)) mux.Handle("/path_implies_body/00A1_End", ch00A1.EndFn(ctxHandler)) mux.Handle("/path_implies_body/100A1_End", ch100A1.EndFn(ctxHandler)) server := httptest.NewServer(mux) rBody0, err := getReqBody(server.URL + "/path_implies_body/00_End") if err != nil { fmt.Println(err) } rBody1, err := getReqBody(server.URL + "/path_implies_body/00A1_End") if err != nil { fmt.Println(err) } rBody2, err := getReqBody(server.URL + "/path_implies_body/100A1_End") if err != nil { fmt.Println(err) } fmt.Println("Chain 0 Body:", rBody0) fmt.Println("Chain 1 Body:", rBody1) fmt.Println("Chain 2 Body:", rBody2) } func getReqBody(url string) (string, error) { resp, err := http.Get(url) if err != nil { return "", err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } _ = resp.Body.Close() return string(body), nil } func ctxHandlerWrapper0(n chain.Handler) chain.Handler { return chain.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(bTxt0)) n.ServeHTTPContext(ctx, w, r) _, _ = w.Write([]byte(bTxt0)) }) } func ctxHandlerWrapper1(n chain.Handler) chain.Handler { return chain.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(bTxt1)) n.ServeHTTPContext(ctx, w, r) _, _ = w.Write([]byte(bTxt1)) }) } func httpHandlerWrapperA(n http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(bTxtA)) n.ServeHTTP(w, r) _, _ = w.Write([]byte(bTxtA)) }) } func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(bTxtEnd)) return }
Output: Chain 0 Body: 00_END_00 Chain 1 Body: 00A1_END_1A00 Chain 2 Body: 100A1_END_1A001
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Chain ¶
type Chain struct {
// contains filtered or unexported fields
}
Chain holds the basic components used to order Handler wrapper chains.
func (Chain) Append ¶
Append takes one or more Handler wrappers, and appends the value to the returned Chain.
func (Chain) EndFn ¶
func (c Chain) EndFn(h HandlerFunc) http.Handler
EndFn takes a func that matches the HandlerFunc type, then passes it to End.
type Handler ¶
Handler interface must be implemented for a function to be able to be wrapped, or served.
type HandlerFunc ¶
HandlerFunc is an adapter which allows a function with the appropriate signature to be treated as a Handler.
func (HandlerFunc) ServeHTTPContext ¶
func (h HandlerFunc) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request)
ServeHTTPContext calls h(ctx, w, r)