If you have been a developer for several years, maybe you have been in a situation where you need to store some data and then be able to share that data between different modules within an application.
Context
For example, let's suppose we have a configuration struct like this:
config := Config{
TrackClicks: true,
TrackOpens: true,
}
Let's say we get that configuration from a request. Now that we have that configuration struct, how do we share it with other handlers in our application?
The Gorila Web Toolkit project has an easy solution for that! The context
package allows you to store values in a global and thread-safe fashion.
The first thing we need to do is to get it using go get github.com/gorilla/context
, then we only need to include it in our package with import "github.com/gorilla/context"
So we could use it like this:
type contextString string
const ConfigKey contextString = "context"
func SetConfigHandler(w http.ResponseWriter, r *http.Request) {
var config Config
//...Getting the config data from request...
context.Set(r, ConfigKey, config)
}
func GetClicksHandler(w http.ResponseWriter, r *http.Request) {
config := context.Get(r, ConfigKey).(Config)
if config.TrackClicks{
WriteNumberClicks(w)
}
}
First, we declare the custom type contextString
in order to avoid name collisions. Then we create the constant ConfigKey
that we will use as key for storing and retrieving the configuration struct from the context.
After that, we store the configuration object once we've got the data from the request using context.Set
.
Finally we can get the configuration object from the context using context.Get
Lastly, if at some point we need to get rid of all the stuff we saved in the context we only need to call context.Clear
Sessions
The Gorilla Web Toolkit also has another package to store data globally, it is called sessions
. This package allows us to store data using cookies.
Again, first we need to get the package with go get github.com/gorilla/sessions
, then we import it using import "github.com/gorilla/sessions"
.
Then we can use it like this:
var store = sessions.NewCookieStore([]byte("Cr0wd1nt"))
func SetConfigHandler(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "my-session")
session.Values["trackClicks"] = true
session.Values["trackOpens"] = true
session.Save(r, w)
}
To begin, we create a session store with sessions.NewCookieStore
passing a secret key used to authenticate the session. Then we are able to get the session using store.Get
, this method always returns a session, even if empty. After that, add some values to the session hash. And finally, we save the session data.
It's worth mentioning that if you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler to avoid memory leaks.
The easiest way to do this is wrapping the top-level mux when calling http.ListenAndServe, like this: http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
.
Conclusion
As we can see, the Gorilla Web Toolkit offers these two very easy-to-use tools that allow us to store data globally. It's just our choice wether to use one or the other. If we need to store custom structs of data, then our better option is to use the context
package. But if we only need to store bits of data, like session data from a request; our best option is to use the session package.
Leave questions or comments in the section below. And thanks for reading!