Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to pass information back to middleware? #914

Open
koote opened this issue May 14, 2024 · 2 comments
Open

How to pass information back to middleware? #914

koote opened this issue May 14, 2024 · 2 comments

Comments

@koote
Copy link

koote commented May 14, 2024

The problem is in middleware some information is unknown, those information can only be determined later.
For example, I have an instrumentation middleware, which measures the request handling time (egress - ingress), and logs the error when request handling hit any errors, obviously those kind of information is only available when request reaches the handler implements business logic. When instrumentation middleware receives the request, it has no way to know how long will processing current request take or whether current request will encounter any errors.

However, in golang the only way to pass information when process http request is using the context object, the information flows from upstream to downstream, I can wrap any values or objects into context using context.WithValue and export the key, downstream modules can use the key to extract those data out from context, but I cannot do it in reverse order, passing the information from downstream back to upstream modules like middleware.

Seems I need a mechanism to setup a callback hook in http process pipeline, when request pops up from the stack/pipeline, but I cannot find such a mechanism is supported by go-chi, does anyone have a good suggestion on this? Thanks.

@VojtechVitek
Copy link
Contributor

Each middleware that needs to bubble up information from handlers downstream needs to create their own storage in the context, e.g. a pointer to a value that will be filled downstream.

There's no other way around, as contexts get unwrapped on a way back up.

I agree it would be useful to have a common middleware pkg for this.

@koote
Copy link
Author

koote commented May 16, 2024

Each middleware that needs to bubble up information from handlers downstream needs to create their own storage in the context, e.g. a pointer to a value that will be filled downstream.

There's no other way around, as contexts get unwrapped on a way back up.

I agree it would be useful to have a common middleware pkg for this.

Thanks @VojtechVitek, are you suggesting that, I can do like this:

type contextKey struct {
    name string
}

var (
    ErrorKey = &contextKey{"error"}
)

func Middleware() func(http.Handler) http.Handler {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
            var finalError error
            ctx := req.Context()
            ctx = context.WithValue(ctx, ErrorKey, &finalError)
            h.ServeHTTP(rw, req.WithContext(ctx))
       })
    }
}

Then extract the value and fill it:

something, err := processTheRequest(req)
if err != nil {
    errorVal = context.Value(middleware.ErrorKey)
    errorVal = &err
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants