I'm trying to build a very simple Go web application, and the golang "a folder per package" structure is making things difficult for me.
I'm using github.com/gorilla/mux
as the router and github.com/unrolled/render
for template rendering. This means that I need to create a new router and a new renderer when the app launches, and I need all my routes to access the renderer.
This is super easy to do in a single file:
func main() {
...
r := render.New(render.Options{
// a lot of app specific setup
})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
r.HTML(w, http.StatusOK, "myTemplate", nil)
})
...
}
However, this is where I don't understand Go. Because I want the routes in separate files in a subfolder (my project will grow), that forces them to be in a routes
package. Of course that makes the renderer variable inaccesssible. I can't just create the renderer in the routes
package, because the render.New()
call relies on a me passing in a ton of app specific stuff like the template folder, and helpers for asset paths.
I went down the route of making my handler functions work on a struct with an already initialized renderer...
func (app *App) Hello2(w http.ResponseWriter, r *http.Request) {
app.Renderer.HTML(w, http.StatusOK, "myTemplate", nil)
}
But I'm still confused as to how I'm going to access this app *App
in the routes
package when it's initialized in main
. Everything in Go seems super easy if you have a flat list of files, but as soon as you want a bit of folder structure, the package setup becomes problematic.
There's probably something I'm missing here, so any help is appreciated.
Here's general info on dealing with dependencies in Go. A key trick is, you just have to declare the
Render
variable in a package that your views can import. You could create amyapp/render
package with avar Render
that's either inited in the package itself (func init()
) or set frommain
.But the context thing you found sounds totally sane, though it might be more than this app needs. The neat thing about it is that because the context is set in per-request code, later you could extend it to do sneaky things like use the
Host:
header to provide a differentLayout
for people loading the app via different domains. If theLayout
is baked into a global, you can't. This can be a real advantage--I've tried to retrofit per-request changes onto big codebases whose config was sprayed around various global variables, and it's a pain.