Hook for Propagating Context/Headers #57
-
We have a microservice architecture and platform-mandated standards to propagate specific fields/headers throughout all calls. Example: Browser -> Service A -> Service B -> Service C For tracing/logging, we propagate a few headers in every request, such as X-Request-ID, X-Forward-For, and X-Real-IP. Today we handle this by having a small wrapper around http.Client and adding a Before hook that has the following signature.
The before hook executes before calling Do method on http.Client. Basically, it provides an opportunity to modify the request before its sent to the server. We use it to pull values from the context and set the request headers. Example below:
Since this is a common pattern, I'm looking for the best way to accomplish this pattern within requests. From glancing at the API/code I'm seeing three possible approaches.
Option 3 sounds dicey, though, looking at the docs in the standard library.
What might be useful, although admittedly I haven't thought it all the way through, would be for the builder to provide a hook that took a context.Context and the raw *http.Request object. Then inside the Request method, before returning the request, the hook function could execute, allowing the headers to be populated based on values in the context. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
In terms of the warning from the standard library, that's why you need to clone a request before modifying it in a transport. See the UserAgentTransport for example, which adds a header to the cloned request. Another option which you haven't listed is creating a request.Config like func CtxConfig(ctx context.Context) request.Config {
return func(rb *Builder) {
requestId := ctx.Value(ContextXRequestID).(string)
realIP := ctx.Value(ContextXRealIP).(string)
forwardFor := ctx.Value(ContextXForwardFor).(string)
uid := ctx.Value(ContextUID).(string)
rb.Header("X-Request-ID", requestId)
rb.Header("X-Real-IP", realIP)
rb.Header("X-Forwarded-For", forwardFor)
rb.Header("X-App-User-ID", uid)
}
}
err := requests.URL(myurl).Config(CtxConfig(ctx)).Fetch(ctx) But I think the custom transport is probably the best option. |
Beta Was this translation helpful? Give feedback.
In terms of the warning from the standard library, that's why you need to clone a request before modifying it in a transport. See the UserAgentTransport for example, which adds a header to the cloned request.
Another option which you haven't listed is creating a request.Config like