8

As the documentation said

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx

but I found, in the typical http request handle function, a http.Request object has .Context() method can retrieve the context which http request associate with.

So why recommend to use context as the first parameter in these functions? Is that reasonable in this situation?


I know that is not an absolute rule. But I want to know why the HandlerFunc is func(ResponseWriter, *Request) instead of func(context.Context, ResponseWriter, *Request).

Apparently HandlerFunc breaks this recommendation.

kubanczyk
  • 5,184
  • 1
  • 41
  • 52
Neo Ko
  • 1,365
  • 15
  • 25
  • The recommendation is a good one, stick to it. Note that for package http the Context hat to be retrofitted without breaking compatibility. Nothing to see here. – Volker May 25 '18 at 06:20
  • It's a convention. Like "error first callback" in node. – ain May 25 '18 at 06:26
  • @Volker So you mean the reason why `.Context()` was added just for not to break compatibility? That's not a best practice? – Neo Ko May 25 '18 at 06:28
  • 1
    Yes and this **is** best practice. Breaking a guaranteed compatibility promise would be awful practice. – Volker May 25 '18 at 07:11
  • `req.Context()` is nothing to do with breaking backwards-compatibility? the request stores a context so that you can retrieve it whenever you like (given `http.Request` is a value object in this sense) – JamesHalsall Mar 17 '22 at 11:45

1 Answers1

11

As described in the documentation you quoted above, ctx should be a (very) common argument for many functions. This is similar to the way many functions return an error. The best place for a common argument/return value is either as the first, or last in a list. (Arguably, Go could have chosen to make error always be the first return value--I won't discuss that here).

Since variadic variables may only be the last in the list of function arguments, this leaves the only option for a common argument to be the first one.

I expect this is why ctx is always first.

This pattern is often seen with other variables in Go (and other languages) as well. Any time a common variable is used by a set of related functions, that common variable often comes first in the argument list (or possibly second, after ctx).


Contrary to the advice you quoted, there are libraries that store ctx in a struct, rather than passing it around as the first argument. These are usually (always?) libraries which had to be retro-fitted to use ctx, long after the library contract was set in stone (by the Go 1.x compatibility guarantee).

Generally, you should follow the advice to pass ctx as the first argument, for any new work.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Thank you, as a newcomer the difference in `http` package really make me confused – Neo Ko May 25 '18 at 07:16
  • 1
    Reasons for not storing contexts in a struct are explained in a more recent post on the official blog: https://go.dev/blog/context-and-structs – jub0bs Oct 27 '22 at 06:26