middleware.go raw

   1  package middleware
   2  
   3  import (
   4  	"context"
   5  )
   6  
   7  // Handler provides the interface for performing the logic to obtain an output,
   8  // or error for the given input.
   9  type 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.
  19  type 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.
  24  func (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.
  31  type 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.
  45  type 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.
  54  func (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.
  62  func 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  }
  72