How can I combine Go middleware pattern with error returning request handlers?

后端 未结 4 1934
青春惊慌失措
青春惊慌失措 2021-01-05 02:39

I am familiar with the Go middleware pattern like this:

// Pattern for writing HTTP middleware.
func middlewareHandler(next http.Handler) http.Handler {
             


        
4条回答
  •  执笔经年
    2021-01-05 03:22

    I like this pattern of HandlerFuncs returning errors too, it's much neater and you just write your error handler once. Just think of your middleware separately from the handlers it contains, you don't need the middleware to pass errors. The middleware is like a chain which executes each one in turn, and then the very last middleware is one which is aware of your handler signature, and deals with the error appropriately.

    So in it's simplest form, keep the middleware you have exactly the same, but at the end insert one which is of this form (and doesn't execute another middleware but a special HandlerFunc):

    // Use this special type for your handler funcs
    type MyHandlerFunc func(w http.ResponseWriter, r *http.Request) error
    
    
    // Pattern for endpoint on middleware chain, not takes a diff signature.
    func errorHandler(h MyHandlerFunc) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
           // Execute the final handler, and deal with errors
            err := h(w, r)
            if err != nil {
                // Deal with error here, show user error template, log etc
            }
        })
    }
    

    ...

    Then wrap your function like this:

    moreMiddleware(myMiddleWare(errorHandler(myhandleFuncReturningError)))
    

    That means this special error middleware can only ever wrap your special function signature, and come at the end of the chain, but that's fine. Also I'd consider wrapping this behaviour in your own mux to make it a little simpler and avoid passing error handlers around, and let you build a chain of middleware more easily without having ugly wrapping in your route setup.

    I think if you're using a router library, it needs explicit support for this pattern to work probably. You can see an example of this in action in a modified form in this router, which uses exactly the signatures you're after, but handles building a middleware chain and executing it without manual wrapping:

    https://github.com/fragmenta/mux/blob/master/mux.go

提交回复
热议问题