Middleware
A middleware consists of a function that accepts and returns a endpoint or a transport specific handler.
Endpoint Middlewares
Endpoint middlewares operate at the endpoint level and are transport agnostic. They consist of functions that accept and return a Goa endpoint. Here is an example of an endpoint middleware that logs errors:
// ErrorLogger is an endpoint middleware that logs errors using the given
// logger. All log entries start with the given prefix.
func ErrorLogger(l *log.Logger, prefix string) func (goa.Endpoint) goa.Endpoint {
return func(e goa.Endpoint) goa.Endpoint {
// A Goa endpoint is itself a function.
return goa.Endpoint(func (ctx context.Context, req interface{}) (interface{}, error) {
// Call the original endpoint function.
res, err := e(ctx, req)
// Log any error.
if err != nil {
l.Printf("%s: %s", prefix, err.Error())
}
// Return endpoint results.
return res, err
})
}
}
The service code generated by Goa defines a Use
method that applies the
middleware to all endpoints defined by the service. Alternatively the middleware
can be applied to specific endpoints by wrapping the corresponding endpoints
struct field.
import (
calcsvc "goa.design/examples/basic/gen/calc"
calc "goa.design/examples/basic"
)
func main() {
// ...
var svc calcsvc.Service
{
svc = calc.NewCalc(logger)
}
var eps *calcsvc.Endpoints
{
eps = calcsvc.NewEndpoints(svc)
// Apply ErrorLogger to all endpoints.
calcsvc.Use(ErrorLogger(logger, "calc"))
// Or apply ErrorLogger to specific endpoint.
// eps.Add = ErrorLogger(logger, "add")(eps.Add)
}
// ...
}
Transport Middlewares
Transport middlewares operate at the transport layer. They apply to HTTP handlers or gRPC methods.
HTTP Middlewares
A HTTP middlewares is a function that takes and returns a HTTP handler.
Here is an example of a HTTP middleware that reads the value of the
X-Request-Id
request header and writes it in the request context if present.
// InitRequestID is a HTTP server middleware that reads the value of the
// X-Request-Id header and if present writes it in the request context.
func InitRequestID() func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
// A HTTP handler is a function.
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req := r
// Grab X-Request-Id header and initialize request context with it.
if id := r.Header.Get("X-Request-Id"); id != "" {
ctx = context.WithValue(r.Context(), RequestIDKey, id)
req = r.WithContext(ctx)
}
// Call initial handler.
h.ServeHTTP(w, req)
})
}
}
HTTP middlewares can be applied using the generated Use
method on the HTTP
server. This method applies the middleware to all the server handlers.
Alternatively the middleware may be applied to a specific server handler
similarly to how endpoint middlewares may be applied to a specific endpoint.
HTTP middlewares may also be mounted directly on the
goa Muxer to execute the
middleware on all requests independently of any handler.
func main() {
// ...
var mux goahttp.Muxer
{
mux = goahttp.NewMuxer()
}
var calcServer *calcsvcsvr.Server
{
calcServer = calcsvcsvr.New(calcEndpoints, mux, dec, enc, errorHandler(logger))
// Apply InitRequestID middleware to all server handlers.
calcServer.Use(InitRequestID())
}
// Alternatively apply middleware to all requests.
// var handler http.Handler = mux
// handler = InitRequestID()(handler)
// ... Now use handler to start the HTTP server instead of mux.
}
Goa has implementations for the following HTTP middlewares:
- Logging server middleware.
- Request ID server middleware.
- Tracing middleware for server and client
- AWS X-Ray middleware for server and client.
gRPC Middleware
gRPC middlewares are gRPC transport specific and consist of server and client gRPC interceptors.
- UnaryServerInterceptor and UnaryClientInterceptor for unary endpoints.
- StreamServerInterceptor and StreamClientInterceptor for streaming endpoints.
Goa implements the following gRPC middlewares:
- Logging server middleware for unary and streaming endpoints.
- Request ID server middleware for unary and streaming endpoints.
- Stream Canceler server middleware.
- Tracing middleware for unary server and client and streaming server and client.
- AWS X-Ray middleware for unary and streaming client and server.
Refer to the tracing example for an illustration of how gRPC middlewares may be applied to gRPC endpoints.