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)