-1

Is there any option to get current request object (struct) outside http.HandlerFunc? I'm facing problem that I need unique random hash per request only, I can't use global variable because in case my application will handle 2 or more requests at the same time, each request will override global variable value.

I figured out that I can use context like this:

func Init() Middleware {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
            ctx := context.WithValue(request.Context(), "requestId", GetRequestHash())

            next.ServeHTTP(writer, request.WithContext(ctx))
        })
    }
}

Then in HandlerFunc I can get this unique hash

request.Context().Value("requestId")

but the problem is that I need this value very very deep down my application and I can't just pass this hash by parameter. I have many handlers already written and this handlers calls function that calls another... I need something like http.GetCurrentRequest somewhere outside the HandlerFunc to get request context and finally to get requestId (unique hash per request).

Obviously I can not just save this hash value as global variable because it will be overriden by other request...

Mariusz Jucha
  • 141
  • 1
  • 3
  • 11
  • 3
    That is what context is used for. You need to pass the context. – Burak Serdar Apr 08 '20 at 15:00
  • 2
    "Is there any option to get current request object (struct) outside http.HandlerFunc?" No. Do what you found out, it works. – Volker Apr 08 '20 at 15:11
  • Well but still I will need to pass context to functions I use in handler func, then these functions needs to pass context on to other functions... – Mariusz Jucha Apr 08 '20 at 15:13
  • 4
    Yes, that's how you use a context. It contains values and cancellation. You could just pass the values if there's nothing you can do with the cancellation notification. – JimB Apr 08 '20 at 15:15

1 Answers1

1

I think that you're looking for a threadlocal equivalent which is not supported in Go. There are packages that accomplishes thread local storage, but I do not want to recommend them because the Go team recommends contexts (see below link).

Some alternative (and not necessarily good) options

  • Store the hash in some go code (using appropriate locks for concurrency scenarios).
  • Use a datastore (like a Redis) to store these values instead.

Preferred option - use the context package

In the go developer blog, the context package was specifically designed for this scenario. It allows the developer to pass through values (like the hash mentioned in the thread), as well as the ability to cancel the context (thereby cancelling the underlying goroutine) when requests are too long for a particular use case.

Shiraaz.M
  • 3,073
  • 2
  • 24
  • 40