Is it possible to not copy paste expression commonHanlder(handler1), commonHanlder(handler2) ... commonHanlder(handlerN) in this code:
rtr.HandleFunc("/", commonHanlder(handler1)).Methods("GET")
rtr.HandleFunc("/page2", commonHanlder(handler2)).Methods("GET")
and set it in one place like
http.ListenAndServe(":3000", commonHanlder(http.DefaultServeMux))
But this variant is not working and gives two errors on compile:
./goRelicAndMux.go:20: cannot use http.DefaultServeMux (type *http.ServeMux) as type gorelic.tHTTPHandlerFunc in argument to commonHanlder
./goRelicAndMux.go:20: cannot use commonHanlder(http.DefaultServeMux) (type gorelic.tHTTPHandlerFunc) as type http.Handler in argument to http.ListenAndServe:
gorelic.tHTTPHandlerFunc does not implement http.Handler (missing ServeHTTP method)
The full code:
package main
import (
"github.com/gorilla/mux"
"github.com/yvasiyarov/gorelic"
"log"
"net/http"
)
func main() {
initNewRelic()
rtr := mux.NewRouter()
var commonHanlder = agent.WrapHTTPHandlerFunc
rtr.HandleFunc("/", commonHanlder(handler1)).Methods("GET")
rtr.HandleFunc("/page2", commonHanlder(handler2)).Methods("GET")
http.Handle("/", rtr)
log.Println("Listening...")
http.ListenAndServe(":3000", http.DefaultServeMux)
}
func handler1(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("mainPage"))
}
func handler2(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("page 2"))
}
var agent *gorelic.Agent
func initNewRelic() {
agent = gorelic.NewAgent()
agent.Verbose = true
agent.NewrelicName = "test"
agent.NewrelicLicense = "new relic key"
agent.Run()
}
It seems like you want to call commonHandler on the root of your application and have it work for all. Since you are using mux, just wrap the mux router once.
func main() {
initNewRelic()
rtr := mux.NewRouter()
var commonHandler = agent.WrapHTTPHandler
rtr.HandleFunc("/", handler1).Methods("GET")
rtr.HandleFunc("/page2", handler2).Methods("GET")
http.Handle("/", commonHandler(rtr))
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
I also removed the http.DefaultServeMux reference in ListenAndServe since passing nil will automatically use the default.
Related
I am fairly new to Go and have not been able to find any information on this, maybe it is just not possible at this time.
I am trying to delete or replace a mux route (using http.NewServeMux, or gorilla's mux.Router). My end goal is to be able to enable/disable a route or set of routes without having to restart the program.
I can probably accomplish this on a handler to handler basis and just return 404 if that feature is "disabled", but I would rather find a more general way to do this since I would like to implement it for every route in my application.
Or would I be better off just keeping track of disabled url patterns and using some middleware to prevent handler execution?
If someone can at least point me in the right direction, I will absolutely post code examples of a solution assuming there is one. Thanks!
There's no built in way, but it is easy enough to implement play.
type HasHandleFunc interface { //this is just so it would work for gorilla and http.ServerMux
HandleFunc(pattern string, handler func(w http.ResponseWriter, req *http.Request))
}
type Handler struct {
http.HandlerFunc
Enabled bool
}
type Handlers map[string]*Handler
func (h Handlers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if handler, ok := h[path]; ok && handler.Enabled {
handler.ServeHTTP(w, r)
} else {
http.Error(w, "Not Found", http.StatusNotFound)
}
}
func (h Handlers) HandleFunc(mux HasHandleFunc, pattern string, handler http.HandlerFunc) {
h[pattern] = &Handler{handler, true}
mux.HandleFunc(pattern, h.ServeHTTP)
}
func main() {
mux := http.NewServeMux()
handlers := Handlers{}
handlers.HandleFunc(mux, "/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this will show once"))
handlers["/"].Enabled = false
})
http.Handle("/", mux)
http.ListenAndServe(":9020", nil)
}
Yes you can.
One way to do it is to have a sturct that implement http.Handle interface with the method
ServeHTTP.
Then have the struct contain another muxer like gorilla's
and finally have an atomic Switch to enable/ disable the subrouting
This is a working example of what I mean:
package main
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
"sync/atomic"
)
var recording int32
func isRecording() bool {
return atomic.LoadInt32(&recording) != 0
}
func setRecording(shouldRecord bool) {
if shouldRecord {
atomic.StoreInt32(&recording, 1)
} else {
atomic.StoreInt32(&recording, 0)
}
}
type SwitchHandler struct {
mux http.Handler
}
func (s *SwitchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if isRecording() {
fmt.Printf("Switch Handler is Recording\n")
s.mux.ServeHTTP(w, r)
return
}
fmt.Printf("Switch Handler is NOT Recording\n")
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "NOT Recording\n")
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/success/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Recording\n")
})
handler := &SwitchHandler{mux: router}
setRecording(false)
http.Handle("/", handler)
http.ListenAndServe(":8080", nil)
}
According to https://github.com/gorilla/mux/issues/82 it is suggested to swap the router instead of deleting routes. Existing connections will stay open.
I'm trying to get my hands dirty while playing with some Gorilla/Mux and Go-Redis but I'm facing a little implementation problem here.
Essentially I have a project structured like the following:
Where redismanager.go handles the initialization of a Redis Client:
package redismanager
import (
"fmt"
"github.com/go-redis/redis"
)
func InitRedisClient() redis.Client {
client := redis.NewClient(&redis.Options{
Addr : "localhost:6379",
Password: "",
DB : 0, //default
})
pong, err := client.Ping().Result()
if( err != nil ){
fmt.Println("Cannot Initialize Redis Client ", err)
}
fmt.Println("Redis Client Successfully Initialized . . .", pong)
return *client
}
Where main.go calls redismanager.InitRedisClient and initializes mux.Handlers:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
type RedisInstance struct {
RInstance *redis.Client
}
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).
Methods("POST")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
Now, I can easily define and let work properly AddTodoHandler in the same file like:
func (c *RedisInstance) AddTodoHandler(w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
But, to make things a bit more modular, I'm trying to move all of these RouteHandlers inside their respective files in api package. In order to make that, I need to pass a reference to redisHandler but I'm having some difficulties when trying to make that with an Handler inside api package.
For instance, If in the main I add:
r.HandleFunc("/todo/{id}", api.GetTodoHandler(&client)).
Methods("GET")
with gettodo.go
package api
import (
"net/http"
"github.com/gorilla/mux"
"fmt"
"encoding/json"
"github.com/go-redis/redis"
)
func GetTodoHandler(c *RedisInstance) func (w http.ResponseWriter, r *http.Request) {
func (w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
}
It works nicely.
I'm still pretty new to Go and haven't found any cleaner solution to that even after several researches and reads.
Is my approach correct or are there any better ones?
Write a function that converts a function with the Redis instance argument to an HTTP handler:
func redisHandler(c *RedisInstance,
f func(c *RedisInstance, w http.ResponseWriter, r *http.Request)) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { f(c, w, r) })
}
Write your API handlers like this:
func AddTodoHandler(c *RedisInstance, w http.ResponseWriter, r *http.Request) {
...
}
Add to the mux like this:
r.Handler("/todo", redisHandler(client, api.AddTodoHandler)).Methods("POST")
where client is the Redis instance.
I would recommend using an App struct which initializes DB and Routes. And all Redis methods will be called inside.
e.g. type App struct{Routes *mux.Router, DB *DB_TYPE}
And which will have App.initializeRoutes method.
type App struct {
Router *mux.Router
DB *redis.NewClient
}
func (a *App) Run(addr string) {
log.Fatal(http.ListenAndServe(":8000", a.Router))
}
func (a *App) Initialize(addr, password string, db int) error {
// Connect postgres
db, err := redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})
if err != nil {
return err
}
// Ping to connection
err = db.Ping()
if err != nil {
return err
}
// Set db in Model
a.DB = db
a.Router = mux.NewRouter()
a.initializeRoutes()
return nil
}
func (a *App) initializeRoutes() {
a.Router.HandleFunc("/todo", a.AddTodoHandler).Methods("POST")
a.Router.HandleFunc("/todo/{id}", a.GetTodoHandler).Methods("GET")
}
// AddTodoHandler has access to DB, in your case Redis
// you can replace the steps for Redis.
func (a *App) AddTodoHandler() {
//has access to DB
a.DB
}
Hope you get the point, you can even extract out the Model work into a separate Struct and then pass it inside func's
r.HandleFunc("/todo/{id}", redisHandler.api.GetTodoHandler).Methods("GET")
Your redisHandler, as defined in main, has no api field, so this naturally doesn't compile.
If you re-defined your RedisInstance type in the api package, and you defined the handler methods on that type in the method-specific files, then you can initialize your redisHandler using that api.RedisInstance type and you can delete the main.RedisInstance type definition:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &api.RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).Methods("POST")
r.HandleFunc("/todo/{id}", redisHandler.GetTodoHandler).Methods("GET")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
I am trying to write a simple http MiddleWare handler that will process an http response. Unfortunately, it does not work and I cannot figure out what mistake I am making. Any/all help is appreciated!
I am using Go Gorilla mux router
Here are illustrative parts of the code:
import (
"fmt"
"log"
"github.com/gorilla/mux"
)
:
func Start() {
router := mux.NewRouter()
router.HandleFunc("/", myHandler)
:
log.Fatal(http.ListenAndServe(":8088", Middleware(router)))
}
func myHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "myHandler called")
}
func Middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
neww := NewProcessor(w)
h.ServeHTTP(neww, r)
})
}
type Processor struct {
http.ResponseWriter
}
func (r *Processor) Write(b []byte) (int, error) {
fmt.Printf("******* Processor writing...")
log.Print(string(b)) // log it out
return r.Write(b) // pass it to the original ResponseWriter
}
func NewProcessor(w http.ResponseWriter) http.ResponseWriter {
fmt.Printf("******* Creating new Processor...")
return &Processor{ResponseWriter: w}
}
The output I get is listed below (extra logging text omitted for clarity):
******* Creating new Processor
myHandler called
However, notice the message "******* Processor writing..." was not displayed, suggesting that the "Write" function did not get called.
What changes need to be made to allow the "Write" function to be called?
return r.Write(b) caused an infinite loop of calls to the Processor's Write() method. Replacing it with return r.ResponseWriter.Write(b) fixed the bug.
Here is the corrected code:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", myHandler)
log.Fatal(http.ListenAndServe(":8088", Middleware(mux)))
}
func myHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "myHandler called")
}
func Middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
new := NewProcessor(w)
h.ServeHTTP(new, r)
})
}
type Processor struct {
http.ResponseWriter
}
func (r *Processor) Write(b []byte) (int, error) {
log.Print("******* Processor writing...")
log.Print(string(b)) // log it out
return r.ResponseWriter.Write(b) // pass it to the original ResponseWriter
}
func NewProcessor(w http.ResponseWriter) http.ResponseWriter {
log.Print("******* Creating new Processor...")
return &Processor{ResponseWriter: w}
}
Output:
2016/07/21 22:59:08 ******* Creating new Processor...
2016/07/21 22:59:08 ******* Processor writing...
2016/07/21 22:59:08 myHandler called
i am using Gorilla Mux for writing a REST API and i am having trouble organizing my routes, currently all of my routes are defined in the main.go file like this
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
})
router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
})
router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
})
router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
})
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
so what i want to do is take out and split this route declaration into multiple files, how would i go about doing that? thanks in advance.
You can modularize your routers independently into different packages, and mount them on the main router
Elaborating just a little on the following issue, you can come up with this approach, that makes it quite scalable (and easier to test, to some degree)
/api/router.go
package api
import (
"net/http"
"github.com/gorilla/mux"
)
func Router() *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/", home)
return router
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("hello from API"))
}
/main.go
package main
import (
"log"
"net/http"
"strings"
"github.com/...yourPath.../api"
"github.com/...yourPath.../user"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/", home)
mount(router, "/api", api.Router())
mount(router, "/user", user.Router())
log.Fatal(http.ListenAndServe(":8080", router))
}
func mount(r *mux.Router, path string, handler http.Handler) {
r.PathPrefix(path).Handler(
http.StripPrefix(
strings.TrimSuffix(path, "/"),
handler,
),
)
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Home"))
}
What about something like this ?
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", HelloHandler)
router.HandleFunc("/user", UserHandler)
router.HandleFunc("/route2", Route2Handler)
router.HandleFunc("/route3", Route3Handler)
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
func HelloHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
}
func UserHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
}
func Route2Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
}
func Route3Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
}
That way you can put your handlers in other files, or even other packages.
If you endup with additionnal dependencies like a database, you can even avoid the need of the global var using a constructor trick:
//main.go
func main() {
db := sql.Open(…)
//...
router.HandleFunc("/hello", NewHelloHandler(db))
//...
}
func NewHelloHandler(db *sql.DB) func(http.ResponseWriter, *http.Request) {
return func(res http.ResponseWriter, req *http.Request) {
// db is in the local scope, and you can even inject it to test your
// handler
fmt.Fprintln(res, "Hello")
}
}
I like checking out other projects in github to grab ideas on how to do stuff, and for these cases I usually take a look first at the Docker repo. This is the way they do it:
For the system's routes, define all handlers in system_routes.go and then initialize those routes on a NewRouter function in system.go.
type systemRouter struct {
backend Backend
routes []router.Route
}
func NewRouter(b Backend) router.Router {
r := &systemRouter{
backend: b,
}
r.routes = []router.Route{
local.NewOptionsRoute("/", optionsHandler),
local.NewGetRoute("/_ping", pingHandler),
local.NewGetRoute("/events", r.getEvents),
local.NewGetRoute("/info", r.getInfo),
local.NewGetRoute("/version", r.getVersion),
local.NewPostRoute("/auth", r.postAuth),
}
return r
}
// Routes return all the API routes dedicated to the docker system.
func (s *systemRouter) Routes() []router.Route {
return s.routes
}
Notice that systemRouter implements the router.Router interface and the Routes function returns a []router.Route, and their handlers are defined as
func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
instead of Go's standard http handler:
func(w http.ResponseWriter, r *http.Request)
So there's extra code of theirs to convert a Docker API Handler to a Go HTTP Handler at the makeHttpHandler function.
And finally, to add those routes to their mux router, on their server.go they implement several other functions to add middleware to their handlers.
If this is something that you think it's what you are looking for, then take your time to analyze the Docker code for their routes, and if you need me to elaborate more or if I missed anything, post a comment.
Since I am new to Go, I prefer a less verbose solution. In each module, we can create a Route function that expects a main route pointer and creates sub-routes to it. Our main.go file would be as follows
package main
import (
"net/http"
"github.com/user-name/repo-name/auth"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
auth.Router(r)
http.ListenAndServe(":8080", r)
}
then in auth module, we can create a route file
package auth
import "github.com/gorilla/mux"
func Router(r *mux.Router) {
routes := r.PathPrefix("/auth").Subrouter()
routes.HandleFunc("/register", Register)
}
I'm reasonably new to golang and am trying to do work out the best way to do this idiomatically.
I have an array of routes I am statically defining and passing to gorilla/mux. I am wrapping each handler function with something to time the request and handle panics (mainly so I could understand how the wrapping worked).
I want them each to be able to have access to a 'context' - a struct that's going to be one-per-http-server, which might have things like database handles, config etc. What I don't want to do is use a static global variable.
The way I'm currently doing it I can give the wrappers access to the context structure, but I can't see how to get this into the actual handler, as it wants that to be an http.HandlerFunc. I thought what I could do is convert http.HandlerFunc into a type of my own that was a receiver for Context (and do similarly for the wrappers, but (after much playing about) I couldn't then get Handler() to accept this.
I can't help but think I'm missing something obvious here. Code below.
package main
import (
"fmt"
"github.com/gorilla/mux"
"html"
"log"
"net/http"
"time"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Context struct {
route *Route
// imagine other stuff here, like database handles, config etc.
}
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
index,
},
// imagine lots more routes here
}
func wrapLogger(inner http.Handler, context *Context) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
context.route.Name,
time.Since(start),
)
})
}
func wrapPanic(inner http.Handler, context *Context) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("panic caught: %+v", err)
http.Error(w, http.StatusText(500), 500)
}
}()
inner.ServeHTTP(w, r)
})
}
func newRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
// the context object is created here
context := Context {
&route,
// imagine more stuff here
}
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(wrapLogger(wrapPanic(route.HandlerFunc, &context), &context))
}
return router
}
func index(w http.ResponseWriter, r *http.Request) {
// I want this function to be able to have access to 'context'
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
func main() {
fmt.Print("Starting\n");
router := newRouter()
log.Fatal(http.ListenAndServe("127.0.0.1:8080", router))
}
Here's a way to do it, but it seems pretty horrible. I can't help but think there must be some better way to do it - perhaps to subclass (?) http.Handler.
package main
import (
"fmt"
"github.com/gorilla/mux"
"html"
"log"
"net/http"
"time"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc ContextHandlerFunc
}
type Context struct {
route *Route
secret string
}
type ContextHandlerFunc func(c *Context, w http.ResponseWriter, r *http.Request)
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
index,
},
}
func wrapLogger(inner ContextHandlerFunc) ContextHandlerFunc {
return func(c *Context, w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner(c, w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
c.route.Name,
time.Since(start),
)
}
}
func wrapPanic(inner ContextHandlerFunc) ContextHandlerFunc {
return func(c *Context, w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("panic caught: %+v", err)
http.Error(w, http.StatusText(500), 500)
}
}()
inner(c, w, r)
}
}
func newRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
context := Context{
&route,
"test",
}
router.Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
wrapLogger(wrapPanic(route.HandlerFunc))(&context, w, r)
})
}
return router
}
func index(c *Context, w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q secret is %s\n", html.EscapeString(r.URL.Path), c.secret)
}
func main() {
fmt.Print("Starting\n")
router := newRouter()
log.Fatal(http.ListenAndServe("127.0.0.1:8080", router))
}
I am learning Go and currently in the middle of a nearly identical problem, and this is how I've dealt with it:
First, I think you missed an important detail: There are no global variables in Go. The widest scope you can have for a variable is package scope. The only true globals in Go are predeclared identifiers like true and false (and you can't change these or make your own).
So, it's perfectly fine to set a variable scoped to package main to hold context for your program. Coming from a C/C++ background this took me a little time to get used to. Since the variables are package scoped, they do not suffer from the problems of global variables. If something in another package needs such a variable, you will have to pass it explicitly.
Don't be afraid to use package variables when it makes sense. This can help you reduce complexity in your program, and in a lot of cases make your custom handlers much simpler (where calling http.HandlerFunc() and passing a closure will suffice).
Such a simple handler might look like this:
func simpleHandler(c Context, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// FIXME Do something with our context
next.ServeHTTP(w, r)
})
}
and be used by:
r = mux.NewRouter()
http.Handle("/", simpleHandler(c, r))
If your needs are more complex, you may need to implement your own http.Handler. Remember that an http.Handler is just an interface which implements ServeHTTP(w http.ResponseWriter, r *http.Request).
This is untested but should get you about 95% of the way there:
package main
import (
"net/http"
)
type complicatedHandler struct {
h http.Handler
opts ComplicatedOptions
}
type ComplicatedOptions struct {
// FIXME All of the variables you want to set for this handler
}
func (m complicatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// FIXME Do stuff before serving page
// Call the next handler
m.h.ServeHTTP(w, r)
// FIXME Do stuff after serving page
}
func ComplicatedHandler(o ComplicatedOptions) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
return complicatedHandler{h, o}
}
}
To use it:
r := mux.NewRouter()
// FIXME: Add routes to the mux
opts := ComplicatedOptions{/* FIXME */}
myHandler := ComplicatedHandler(opts)
http.Handle("/", myHandler(r))
For a more developed handler example see basicAuth in goji/httpauth, from which this example was shamelessly ripped off.
Some further reading:
A Recap of Request Handling
Making and Using HTTP Middleware
justinas/alice (for chaining lots of handlers)