middleware.go

 1package middleware
 2
 3import (
 4	"context"
 5)
 6
 7// Handler provides the interface for performing the logic to obtain an output,
 8// or error for the given input.
 9type Handler interface {
10	// Handle performs logic to obtain an output for the given input. Handler
11	// should be decorated with middleware to perform input specific behavior.
12	Handle(ctx context.Context, input interface{}) (
13		output interface{}, metadata Metadata, err error,
14	)
15}
16
17// HandlerFunc provides a wrapper around a function pointer to be used as a
18// middleware handler.
19type HandlerFunc func(ctx context.Context, input interface{}) (
20	output interface{}, metadata Metadata, err error,
21)
22
23// Handle invokes the underlying function, returning the result.
24func (fn HandlerFunc) Handle(ctx context.Context, input interface{}) (
25	output interface{}, metadata Metadata, err error,
26) {
27	return fn(ctx, input)
28}
29
30// Middleware provides the interface to call handlers in a chain.
31type Middleware interface {
32	// ID provides a unique identifier for the middleware.
33	ID() string
34
35	// Performs the middleware's handling of the input, returning the output,
36	// or error. The middleware can invoke the next Handler if handling should
37	// continue.
38	HandleMiddleware(ctx context.Context, input interface{}, next Handler) (
39		output interface{}, metadata Metadata, err error,
40	)
41}
42
43// decoratedHandler wraps a middleware in order to to call the next handler in
44// the chain.
45type decoratedHandler struct {
46	// The next handler to be called.
47	Next Handler
48
49	// The current middleware decorating the handler.
50	With Middleware
51}
52
53// Handle implements the Handler interface to handle a operation invocation.
54func (m decoratedHandler) Handle(ctx context.Context, input interface{}) (
55	output interface{}, metadata Metadata, err error,
56) {
57	return m.With.HandleMiddleware(ctx, input, m.Next)
58}
59
60// DecorateHandler decorates a handler with a middleware. Wrapping the handler
61// with the middleware.
62func DecorateHandler(h Handler, with ...Middleware) Handler {
63	for i := len(with) - 1; i >= 0; i-- {
64		h = decoratedHandler{
65			Next: h,
66			With: with[i],
67		}
68	}
69
70	return h
71}