chain

package module
v2.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2018 License: MIT Imports: 1 Imported by: 1

README

chain

go get github.com/codemodus/chain

Package chain aids the composition of nested http.Handler instances.

Nesting functions is a simple concept. If your nested handler order does not need to be composable, please do not use this or any similar package and avoid adding a dependency to your project.

Usage

type Chain
    func New(handlers ...func(http.Handler) http.Handler) *Chain
    func (c *Chain) Append(handlers ...func(http.Handler) http.Handler) *Chain
    func (c *Chain) Copy(chain *Chain)
    func (c *Chain) End(handler http.Handler) http.Handler
    func (c *Chain) EndFn(handlerFunc http.HandlerFunc) http.Handler
    func (c *Chain) Merge(chains ...*Chain) *Chain
Setup
import (
    // ...

    "github.com/codemodus/chain"
)

func main() {
    // ...

  	// Nested handlers write either "0" or "1" to the response body before
	// and after ServeHTTP() is called.
	//
	// endHandler writes "_END_" to the response body.

	ch00 := New(nestedHandler0, nestedHandler0)
	ch001 := ch00.Append(nestedHandler1)

	ch1 := New(nestedHandler1)
	ch1001 := ch1.Merge(ch001)

	mux := http.NewServeMux()
	mux.Handle("/00_End", ch00.EndFn(endHandler))     // Resp Body: "00_END_00"
	mux.Handle("/001_End", ch001.EndFn(endHandler))   // Resp Body: "001_END_100"
	mux.Handle("/1001_End", ch1001.EndFn(endHandler)) // Resp Body: "1001_END_1001"

    // ...
}
Nestable http.Handler
func nestableHandler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // ...
        
        next.ServeHTTP(w, r)
    	
        // ...
    })
}

More Info

Changes in go1.7+/chain2.0+

As of Go 1.7, the http package's Request type includes a field (accessed via the Context() method) which holds an implementation of context.Context. Further, the context package has been added to the standard library. There is now no need for the custom Handler defined in previous versions of chain. Please refer to the following command to ease the process of updating your source.

sed -r -e 's/chain\.Handler/http.Handler/g' \
    -e 's/[a-zA-Z0-9]+ context\.Context, ([a-zA-Z0-9]+) (http\.ResponseWriter)/\1 \2/' \
    -e 's/ServeHTTPContext\([a-zA-Z0-9]+, /ServeHTTP(/'

Beyond this, any usage of chain.Set(context.Context) will need to be modified manually. Adding the affected logic as a nested handler is a simple and effective alternative. Don't forget to run gofmt/goimports.

Documentation

View the GoDoc

Benchmarks

These results are for comparison of normally nested functions, and chained functions. Each benchmark includes 10 functions prior to the final handler.

go1.7
benchmark             iter      time/iter   bytes alloc         allocs
---------             ----      ---------   -----------         ------
BenchmarkChain10     20000    61.01 μs/op     3684 B/op   51 allocs/op
BenchmarkChain10-4   20000    68.62 μs/op     3691 B/op   51 allocs/op
BenchmarkChain10-8   20000    69.33 μs/op     3696 B/op   51 allocs/op
BenchmarkNest10      20000    60.36 μs/op     3684 B/op   51 allocs/op
BenchmarkNest10-4    20000    70.82 μs/op     3692 B/op   51 allocs/op
BenchmarkNest10-8    20000    71.03 μs/op     3697 B/op   51 allocs/op

Documentation

Overview

Package chain aids the composition of nested http.Handler instances.

Example
// Nested handlers write either "0" or "1" to the response body before
// and after ServeHTTP() is called.
//
// endHandler writes "_END_" to the response body.

ch := chain.New(nestedHandler0, nestedHandler1)
ch = ch.Append(nestedHandler0)

mux := http.NewServeMux()
mux.Handle("/010_End", ch.EndFn(endHandler))

server := httptest.NewServer(mux)

resp, err := respBody(server.URL + "/010_End")
if err != nil {
	fmt.Println(err)
}

fmt.Println("Chain 010 Resp:", resp)
Output:

Chain 010 Resp: 010_END_010
Example (Advanced)
// Nested handlers write either "0" or "1" to the response body before
// and after ServeHTTP() is called.
//
// endHandler writes "_END_" to the response body.

ch00 := chain.New(nestedHandler0, nestedHandler0)
ch001 := ch00.Append(nestedHandler1)

ch1 := chain.New(nestedHandler1)
ch1001 := ch1.Merge(ch001)

mux := http.NewServeMux()
mux.Handle("/00_End", ch00.EndFn(endHandler))
mux.Handle("/001_End", ch001.EndFn(endHandler))
mux.Handle("/1001_End", ch1001.EndFn(endHandler))

server := httptest.NewServer(mux)

resp00, err := respBody(server.URL + "/00_End")
if err != nil {
	fmt.Println(err)
}

resp001, err := respBody(server.URL + "/001_End")
if err != nil {
	fmt.Println(err)
}

resp1001, err := respBody(server.URL + "/1001_End")
if err != nil {
	fmt.Println(err)
}

fmt.Println("Chain 00 Resp:", resp00)
fmt.Println("Chain 001 Resp:", resp001)
fmt.Println("Chain 1001 Resp:", resp1001)
Output:

Chain 00 Resp: 00_END_00
Chain 001 Resp: 001_END_100
Chain 1001 Resp: 1001_END_1001

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chain

type Chain struct {
	// contains filtered or unexported fields
}

Chain contains the current nested http.Handler data.

func New

func New(handlers ...func(http.Handler) http.Handler) *Chain

New receives one or more nested http.Handler instances, and returns a new Chain.

func (*Chain) Append

func (c *Chain) Append(handlers ...func(http.Handler) http.Handler) *Chain

Append receives one or more nested http.Handler instances, and appends the value to the returned Chain.

func (*Chain) Copy

func (c *Chain) Copy(chain *Chain)

Copy receives one Chain instance, and copies it's handlers into the receiver's handlers slice.

func (*Chain) End

func (c *Chain) End(handler http.Handler) http.Handler

End receives an http.Handler, and returns an http.Handler comprised of all nested http.Handler data where the received http.Handler is the endpoint.

func (*Chain) EndFn

func (c *Chain) EndFn(handlerFunc http.HandlerFunc) http.Handler

EndFn receives an instance of http.HandlerFunc, then passes it to End to return an http.Handler.

func (*Chain) Merge

func (c *Chain) Merge(chains ...*Chain) *Chain

Merge receives one or more Chain instances, and returns a merged Chain.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL