Context in Chain of Middlewares

251 views
Skip to first unread message

dc0d

unread,
Nov 2, 2015, 2:55:16 PM11/2/15
to golang-nuts
There are lots of resource about how to share context between members of a chain of http-handlers. I've studied what came in my way and saw different ways of doing it (even written a lib based on Alice that supports context).

There are two main approaches here:

  1. Passing the context object explicitly to the handler.
  2. Sharing the context by other means without changing the signatures.

The first approach seems to be the prominent one and now by popping up the `x/net/context` everywhere, it is even more in demand. The second approach, which can be achieved in different ways (shared map like in gorilla context or use a struct as a context as in gocraft/web) is less popular.

Question: What are Pros & Cons of each approach? Which one is more Godiomatic?

(IMHO) It seems something like:

type Handler2 interface {
http.Handler // embedded classic middleware interface
// ... other parts like (probabely in a lazy manner):
Context() *context.Context
}

Is more suited to solve this problem. Context should be seen as a facility service. What if I do not want Context? To be created and make every request more bloated? And if a problem of a `service` nature gets solved today by means of changing signatures, soon there will be other cases and we will need other signatures.

One could argue that having a context in a chain of request handlers is so essential that changing the signature in the standard lib would worth it & benefits Go ecosystem (& probably he could be right; I don't know. I want to study this). But solving this problem from a `service-like nature` point of view would help with overcoming architectural obstacles, in a more general way (OK; context can be hard coded here; no need for a `that-generic` solution; but it can be a pattern).

And there should be a default plumber (chain-of-http-handlers+context handler) in standard library (or in code of conduct! I see many people give up Go because of Analysis Paralysis phenomena & it should be in attention spot of the community. This happens a lot; far more than expected). 

Matt Silverlock

unread,
Nov 2, 2015, 4:25:20 PM11/2/15
to golang-nuts
There's a discussion on golang-dev about potentially making Context part of the http.Request struct - https://groups.google.com/forum/#!topic/golang-dev/cQs1z9LrJDU

dc0d

unread,
Nov 2, 2015, 4:29:44 PM11/2/15
to golang-nuts
Thank you; I'll read the thread.

John Jeffery

unread,
Nov 2, 2015, 5:56:04 PM11/2/15
to golang-nuts
I have found it very useful being able to pass context through a stack of HTTP handlers, and like you I have been using a small library that passes context and uses a middleware concept based on Alice (https://github.com/spkg/httpctx). Empasis on the *small* library -- it is very straightforward to write something that extends the standard library that suits your purposes. For this reason I would question the urgency to add x/net/context to the standard library or to consider breaking changes to the http library. (Hint: it won't happen).

On the other hand there is some appeal in having support for net/context in the http library in a backwards-compatible way. I think Brad Fitzpatrick has been working on this.


dc0d

unread,
Nov 2, 2015, 7:28:04 PM11/2/15
to golang-nuts
Thanks; to see for myself I've implemented both; previously bob, which needs the signature to changed to accept another parameter as context and classic, which does not need the signature to change but injects the context into a struct. Which on really pays off? I do not know but I like the second approach better because it does not need the http.Handler signature to change and I do not like the context gets instantiated inside request object itself too.

parais...@gmail.com

unread,
Nov 2, 2015, 10:00:25 PM11/2/15
to golang-nuts
I personally think that what may works for the go team may not work for everybody's use case. People shouldn't fear making changes to the way webservers work in Go if it suits their use case better. I personally have my own framework which does dependency injection the same way Martini handles it, even though Martini has been criticized for doing it, because to me it's the best way to handle things like contexts or injecting third party values into http handlers.

I just hate the abuse of closures in a middleware stack. It makes the code hard to read and hard to test. 

So I basically have a router that does type injection or fallback to the classic handlerfunc interface when possible. I 

pass the context directly to the handler as an argument only when needed.

Knowing the core lib is important, but it doesn't mean one should stick to the core lib at all cost. It is not DRY.

Should my solution be in the corelib ? no, nor should the core lib implement a middleware stack. The core lib should , on the other hand make sure everything is an interface to allow developers to take advantage of interfaces in Go , which it does not with http.Handler ( Request is not an interface ).
Reply all
Reply to author
Forward
0 new messages