Golang - Web - Templating

4 April 2015
Tags: golang

Full templating functionality in our website. We want to be able to pass in data to the templates and determine which templates are to be used when generating our response.

This is a continuation of the Golang Web Apps and the source code can be found at https://github.com/reinbach/golang-webapp-guide.

To better organize the code we move all the templating functionality, the templates, and the static files into a separate directory. Which now gives us the following file layout.

.
├── server.go
└── template
    ├── constants.go
    ├── context.go
    ├── html
    │   └── ...
    ├── render.go
    └── static
        └── ...

The render functioned is tweaked in a couple of ways;

  • A context parameter (data for the template) is passed to the render function
  • A list of templates is now expected instead of a single template.

The UpdateTemplateList function is used to prepend the full path to the templates.

#!python
func UpdateTemplateList(tmpls []string) []string {
     d := GetAbsDir("template", TEMPLATE_DIR)
     for i, v := range tmpls {
         tmpls[i] = filepath.Join(d, v)
     }
     return tmpls
 }

And for that we made use of a constant, and so went a step further and moved all our constants into a sepatate constants file, which now has the following;

const (
      STATIC_URL     string = "/static/"
      STATIC_ROOT    string = "static/"
      TEMPLATE_DIR   string = "html/"
      PARENT_PACKAGE string = "template"
 )

If we wanted to rename the directories, we would need to just update this file.

With those above changes we now changed our home and about functions to the following;

func Home(c web.C, w http.ResponseWriter, r *http.Request) {
     ctx := template.NewContext()
     ctx.Add("HomePage", true)
     template.Render(c, w, r, append(templates, "home.html"), ctx)
}


func About(c web.C, w http.ResponseWriter, r *http.Request) {
     ctx := template.NewContext()
     ctx.Add("AboutPage", true)
     template.Render(c, w, r, append(templates, "about.html"), ctx)
}

Lastly we also make use of goji to handle routing and middleware extensibility for us. This requires a small changes to our main function in the server.go file. We simple swap out most of the http.HandleFunc calls with goji.Get and use goji.Serve() instead of the http.ListenAndServe(":8000", nil) So the main function looks like;

func main() {
    http.HandleFunc(template.STATIC_URL, template.StaticHandler)
    goji.Get("/", Home)
    goji.Get("/about", About)
    goji.NotFound(NotFound)


    goji.Serve()
}

As you may have noticed we also added a NotFound to catch any addresses that we cannot resolve.

func NotFound(c web.C, w http.ResponseWriter, r *http.Request) {
    template.Render(c, w, r, append(templates, "404.html"),
        template.NewContext())
}

And now we have a separate module that handles the template rendering and serving of static files for us.