diff --git a/endpoint/endpoint.go b/endpoint/endpoint.go index b259099..7e10380 100644 --- a/endpoint/endpoint.go +++ b/endpoint/endpoint.go @@ -19,3 +19,15 @@ // ContextCanceled indicates the request context was canceled. var ErrContextCanceled = errors.New("context canceled") + +// Chain is a helper function for composing middlewares. Requests will +// traverse them in the order they're declared. That is, the first middleware +// is treated as the outermost middleware. +func Chain(outer Middleware, others ...Middleware) Middleware { + return func(next Endpoint) Endpoint { + for i := len(others) - 1; i >= 0; i-- { // reverse + next = others[i](next) + } + return outer(next) + } +} diff --git a/endpoint/endpoint_example_test.go b/endpoint/endpoint_example_test.go new file mode 100644 index 0000000..dd25ec7 --- /dev/null +++ b/endpoint/endpoint_example_test.go @@ -0,0 +1,50 @@ +package endpoint_test + +import ( + "fmt" + + "golang.org/x/net/context" + + "github.com/go-kit/kit/endpoint" +) + +func ExampleChain() { + e := endpoint.Chain( + annotate("first"), + annotate("second"), + annotate("third"), + )(myEndpoint) + + if _, err := e(ctx, req); err != nil { + panic(err) + } + + // Output: + // first pre + // second pre + // third pre + // my endpoint! + // third post + // second post + // first post +} + +var ( + ctx = context.Background() + req = struct{}{} +) + +func annotate(s string) endpoint.Middleware { + return func(next endpoint.Endpoint) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + fmt.Println(s, "pre") + defer fmt.Println(s, "post") + return next(ctx, request) + } + } +} + +func myEndpoint(context.Context, interface{}) (interface{}, error) { + fmt.Println("my endpoint!") + return struct{}{}, nil +}