Understanding Go’s template package

Satish Manohar Talim
7 min readSep 4, 2015

--

Before we get into this, it’s a very good time to have a very quick look at struct, array and slice in Go as these would be used quite a lot here.

struct

A struct is a collection of fields and is defined with the type and “struct” keywords. An example:

Note that the above struct is visible outside the package it is in, as it starts with a capital letter. Variables X and Y start with a capital letter and are also visible outside the package. Struct fields are accessed using a dot. For example:

You can initialize values by variable name in any order, as follows:

msn2 := My_Struct_Name{Y: “Talim”, X: 15}

Array

In Go, an array is a numbered sequence of elements of a specific length.

In the code snippet below, we create an array “arr” that will hold exactly 5 ints. The type of elements and length are both part of the array’s type. By default, an array is zero-valued, which for ints means zeros.

var arr [5]int

We can set a value at an index using the “array[index] = value” syntax, and get a value with “array[index]”.

We can use the following syntax to declare and initialize an array in one line:

arr2 := [5]int{1, 2, 3, 4, 5}

Slice

A slice is a segment of an array. Like arrays, slices are indexable and have a length. Unlike arrays, this length is allowed to change. Here’s an example of a slice:

var x []int

The only difference between this and an array is the missing length between the brackets. In this case x has been created with a length of 0.

If you want to create a slice you should use the built-in “make” function:

x := make([]int, 5)

This creates a slice that is associated with an underlying int array of length 5. Slices are always associated with some array, and although they can never be longer than the array, they can be smaller.

text/template

Usage:

import “text/template”

Most server-side languages have a mechanism for taking predominantly static pages and inserting a dynamically generated component, such as a list of items. Typical examples are scripts in Java Server Pages, PHP scripting and many others. Go has adopted a relatively simple scripting language in the template package.

The package is designed to take text as input and output different text, based on transforming the original text using the values of an object.

To generate HTML output, we shall soon learn about the package “html/template”, which has the same interface as this package but automatically secures HTML output against certain attacks.

The original source is called a template and will consist of text that is transmitted unchanged, and embedded commands which can act on and change text. The commands are delimited by “{{ … }}”, similar to the JSP commands “<%= … =%>” and PHPs “<?php … ?>”.

A template is applied to a Go object. Fields from that Go object can be inserted into the template, and you can “dig” into the object to find sub-fields, etc. The current object is represented as “.”, so that to insert the value of the current object as a string, you use “{{.}}”. The package uses the “fmt” package by default to work out the string used as inserted values.

To insert the value of a field of the current object, you use the field name prefixed by “.”. For example, if the object is of type:

then you insert the values of Name by —

The name is {{.Name}}.

Thus, templates are a way to merge generic text with more specific text i.e. retain the content that is common in the template and then substitute the specific content as required.

The syntax of such definitions is to surround each template declaration with a “define” and “end” action.

The define action names the template being created by providing a string constant. Here is a simple example:

This defines two templates, T1 and T2, and a third T3 that invokes the other two when it is executed. Finally, it invokes T3. If executed this template will produce the text:

ONE TWO

In Go, we use the template package and methods like “Parse”, “ParseFile”, “Execute” to load a template from a string or file and then perform the merge. The content to merge is within a defined type and that has exported fields, i.e. fields within the struct that are used within the template have to start with a capital letter.

Let us look at a simple example.

Make a new folder and cd to it as follows:

$ mkdir $GOPATH/src/github.com/SatishTalim/texttmpl
$ cd $GOPATH/src/github.com/SatishTalim/texttmpl

In this folder write the program “stud_struct.go” as follows:

You can now run the program by typing:

$ go run stud_struct.go

The output is:

Hello Satish!

Note:

  • “New” allocates a new template with the given name.
  • “Parse” parses a string into a template.
  • To include the content of a field within a template, enclose it within curly braces and add a dot at the beginning. E.g. if Name is a field within a struct and its value needs to be substituted while merging, then include the text “{{.Name}}” in the template. Do remember that the field name has to be present and it should also be exported (i.e. it should begin with a capital letter in the type definition), or there could be errors. All text outside “{{.Name}}” is copied to the output unchanged.
  • We have used the predefined variable “os.Stdout” which refers to the standard output to print out the merged data — “os.Stdout” implements “io.Writer”.
  • “Execute” applies a parsed template to the specified data object, and writes the output to “os.Stdout”.

Let us look at another example.

Make a new folder and cd to it as follows:

$ mkdir $GOPATH/src/github.com/SatishTalim/person
$ cd $GOPATH/src/github.com/SatishTalim/person

In this folder write the program “person.go” as follows:

You can now run the program by typing:

$ go run person.go

The output is:

The name is Satish.
His email id is satish@rubylearning.org
His email id is satishtalim@gmail.com

In the above program, we have “{{range .Emails}}”. With “range” the current object “.” is set to the successive elements of the array or slice Emails.

Variables

The template package allows you to define and use variables. In the above example, how would we print each person’s email address prefixed by their name? Let’s modify the above program.

In the code snippet:

{{range .Emails}}
{{.}}
{{end}}

We cannot access the “Name” field as “.” is now traversing the array elements and the “Name” is outside of this scope. The solution is to save the value of the “Name” field in a variable that can be accessed anywhere in its scope. Variables in templates are prefixed by $. So we write:

{{$name := .Name}}
{{range .Emails}}
Name is {{$name}}, email is {{.}}
{{end}}

The modified program, named “new_person.go” is:

You can now run the program by typing:

$ go run new_person.go

The output is:

Name is Satish, email is satish@rubylearning.org
Name is Satish, email is satishtalim@gmail.com

The Go template package is useful for certain kinds of text transformations involving inserting values of objects. It does not have the power of, say, regular expressions, but is faster and in many cases will be easier to use than regular expressions.

html/template

Usage:

import “html/template”

Package template “html/template” implements data-driven templates for generating HTML output safe against code injection. It provides the same interface as package “text/template” and should be used instead of “text/template” whenever the output is HTML.

Modify dosasite.go to use templates

In an earlier article “Static Sites with Go” we had written a program “dosasite.go” where, in the program, all requests are being handled by our file server. Let’s make a slight adjustment so that it only handles request paths that begin with the pattern “/public/” instead.

fs := http.FileServer(http.Dir(“public”))
http.Handle(“/public/”, http.StripPrefix(“/public/”, fs))

The function StripPrefix returns a handler that serves HTTP requests by removing the given prefix from the request URL’s “Path” and invoking the handler “fs”.

“StripPrefix” handles a request for a path that doesn’t begin with the prefix by replying with an HTTP 404 not found error.

Now you can run program with the go tool:

$ cd $GOPATH/src/github.com/SatishTalim/dosasite
$ go run dosasite.go

Now open http://localhost:4747/public/index.html in your browser. You should see the HTML page we have made.

Next, create a “templates” folder as shown below, containing a “layout.html “file with shared markup, and an “indexnew.html” file with some page-specific content.

Go templates, as discussed before, are essentially just named text blocks surrounded by “{{define}}” and “{{end}}” tags. Templates can be embedded into each other, as we do above where the layout template embeds both the “title” and “body” templates.

The modified “dosasite.go” program is:

In the above program, we’ve added the “html/template” and “path” packages to the “import” statement.

We’ve then specified that all the requests not picked-up by the static file server should be handled with a new “ServeTemplate” function.

In the “ServeTemplate” function, we build paths to the layout file and the template file corresponding with the request. Rather than manual concatenation we use Join, which has the advantage of cleaning the path to help prevent directory traversal attacks.

We then use the ParseFiles function to bundle the requested template and layout into a template set. Finally, we use the ExecuteTemplate function to render a named template in the set, in our case the layout template.

Our code also has some error handling:

  • Send a 404 response if the requested template doesn’t exist.
  • Send a 404 response if the requested template path is a directory.
  • Send and print a 500 response if the “template.ParseFiles” function throws an error.

Special thanks to Alex Edwards whose article has been adapted for this topic.

Mark Bates has a free video on Go Templates.

You may be interested in knowing about Go’s Web Forms and App Engine’s datastore.

--

--

Satish Manohar Talim

Senior Technical Evangelist at GoProducts Engineering India LLP, Co-Organizer GopherConIndia. Director JoshSoftware and Maybole Technologies. #golang hobbyist