My basic main
setup:
muxRouter := mux.NewRouter()
v1Router.Router(muxRouter.PathPrefix("/v1").Subrouter())
http.Handle("/", muxRouter)
n := negroni.Classic()
n.Use(negroni.HandlerFunc(apiRouter.Middleware))
n.UseHandler(muxRouter)
s := &http.Server{
Addr: ":6060",
Handler: n,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
Inside the apiRouter.Middleware
I have set the following context:
context.Set(req, helperKeys.DomainName, "some-value")
However, in some handlerFunc within v1Router.Router
when trying to Get
the context's value, the result is nil:
domain := context.Get(req, helperKeys.DomainName)
fmt.Println("DomainName", domain)
Prints: DomainName <nil>
I know that the Set
method is correct as getting the value immediately after setting it in the apiRouter.Middleware
will return the correct string value.
I ended up using Go 1.7
's built in Context
:
context.Set(req, helperKeys.DomainName, "some-value")
// Replaced with:
ctx := req.Context()
ctx = context.WithValue(ctx, helperKeys.DomainName, "some-value")
req = req.WithContext(ctx)
AND
domain := context.Get(req, helperKeys.DomainName)
// Replaced with:
domain := req.Context().Value(helperKeys.DomainName).(string)
Based on your answer, it looks like you are trying to store a database in the context. I wouldn't suggest doing that. Instead try something like this:
type Something struct {
DB *sql.DB // or some other DB object
}
func (s *Something) CreateUser(w http.ResponseWriter, r *http.Request) {
// use s.DB to access the database
fmt.Fprintln(w, "Created a user...")
}
func main() {
db := ...
s := Something{db}
http.HandleFunc("/", s.CreateUser)
// ... everything else is pretty much like normal.
}
This gives your handlers access to the database while not having to set it on the context every single time. Context values should be reserved for things that you can't possibly set until runtime. For example, a request ID that is specific to that web request. Things that outlive the request don't typically fall into this category, and your DB connection will outlive the request.
If you do actually need context values, you should:
An example of this is shown below, and I talk more about context values in general in this blog post:
type userCtxKeyType string
const userCtxKey userCtxKeyType = "user"
func WithUser(ctx context.Context, user *User) context.Context {
return context.WithValue(ctx, userCtxKey, user)
}
func GetUser(ctx context.Context) *User {
user, ok := ctx.Value(userCtxKey).(*User)
if !ok {
// Log this issue
return nil
}
return user
}