-
Notifications
You must be signed in to change notification settings - Fork 2
handler wrapping
spaceweasel edited this page Feb 21, 2016
·
1 revision
Sometimes you need extra objects in a handler, yet the Context is the only item passed in. For example, you might need a to make calls to a database or some other repository.
func multiline(c *mango.Context) {
id := c.RouteParams["id"]
p := repo.GetPerson(id) // where did this repo object come from?
r:= c.Respond()
r.WithModel(p)
r.WithStatus(http.StatusOK)
}
You could get round the problem using a global variable or making your handler function a closure. Another approach is to use handler wrapping, where a handler is wrapped by another function which returns the required ContextHandlerFunc
type in order to be added to the routing system.
type ContextHandlerFunc func(c *mango.Context)
The basic wrapper pattern takes the destination function as an argument and converts it to a ContextHandlerFunc
which gets returned.
func inject(fn func(c *mango.Context, x X)) mango.ContextHandlerFunc {
return func(c *mango.Context) {
// get required "injectables" here
x:= getX() // e.g. a repository or database transaction
fn(c, x)
}
}//...
//...
// handler function with additional parameter in signature
func handlerDependentOnX(c *mango.Context, x X) {
// ...
s := doSomething(x.Data)
// ...
s += x.SomethingElse(56)
// ...
c.RespondWith(s)
}
//...
// registering the route handlers that require x...
r.Get("/something", inject(handlerDependentOnX))
// other route handlers which may or may not use inject()...
The same approach can be used to control authenticated access to any handler, without needing to change its signature or appear in its code.
r.Get("/home", getHome) // freely accessible to everyone
r.Get("/about", getAbout) // freely accessible to everyone
r.Get("/projects", Auth(getProjects)) // authenticated users only
r.Get("/settings", Auth(getSettings)) // authenticated users only
//...
func Auth(fn func(c *mango.Context)) mango.ContextHandlerFunc {
return func(c *mango.Context) {
if !c.Authenticated(){
// prevent running the main handler function
c.RespondWith("Authentication required!").WithStatus(http.StatusForbidden)
}
fn(c)
}
}