Photo by John Doyle on Unsplash

While developing several full stack apps over the years, I realized some apps don’t need a full-fledged frontend application running. Most of these apps serve static content with dynamic values fitted here and there. For example, consider your social media feed, each post of a certain type looks same but it gets populated with data specific to that user. They use some sort of templating to achieve it.

What are templates?

Templates are essentially text files that are used to create dynamic content. For instance, the following JavaScript function takes “name” as an argument and produces different strings.

We can also use the same principle to generate web pages in Go. Web templates allow us to serve personalized results to users. Generating web templates using string concatenation is a tedious task. It can also lead to injection attacks.

Templates in go

There two packages in go to work with templates:

text/templates (Used for generating textual output) html/templates (Used for generating HTML output safe against code injection)

Both of them basically have the same interface with subtle web-specific differences in the latter like encoding script tags to prevent them from running, parsing maps as JSON in view, and more.

Our first Template

Web template in go

The extension of a template file could be anything. We are using .gohtml so that it is supported development tools across IDEs. “Actions” — data evaluations or control structures — is delimited by {{ and }} . The data evaluated inside it is called a Pipeline. Anything outside them is sent to the output unchanged.

Code to execute the template with data: Use go run main.go to see output

You can parse multiple files on line:10 as comma-separated strings (path to file) or parse all files inside a directory. For example:

tpl, err := template.ParseFiles(“index1.gohtml”, “index2.gohtml”)

tpl, err := template.ParseGlob("views/templates/*")

It returns a template container (here called tpl) and error. We can use our data to execute tpl by calling method Execute. In the case of multiple templates, the name of the template will be passed as 2nd argument while data being 3rd. We define our data structure (here type struct). It could be anything in go slice, map, struct, slice-of-structs, structs-of-slice of structs. We will see each of them shortly. The data is fetched using dot (aka cursor). We use it to access variables of data inside templates. Remember the identifiers in provided data have to start with Capital case. We can use them to initialise a variable inside Actions like $myCoupon := .Coupon . We can output the execution result to the web page or standard output because template Execute method takes any value which implements type Writer interface.

It renders as plain text in output console, but if we use it to send as a response to a web request, it will be rendered as a web page enabling us to use HTML tags.

Standard template output

Web template output

It is preferred to do the parsing job inside init function and execution at required places.

func init() {

// Must is a helper that wraps a function returning

// (*Template, error) and panics if the error is non-nil.

tpl = template.Must(template.ParseGlob(“templates/*”))

}

Using different data structures in web templates

Slice (or Array)

Let’s consider a slice of strings:

Slice of strings in go

This can be used in a template by ranging over the Slice (also array) inside Actions. If the value of the pipeline has length zero, nothing will be executed

otherwise, dot (aka cursor) is set to the successive elements of the Slice (also array) and the template is executed.

Template for range over slice

Web template output

Map

Let’s consider a Map data structure:

Map in go

The value of the pipeline inside Action is a map. If there are no key values pairs in the map, nothing is output, otherwise, dot (aka cursor) is set to the successive elements of the map and template is executed with $key taking each key, $val taking the respective value. If keys are of the basic type with a defined order ("comparable"), the elements will be visited in sorted key order.

Web template for map

Web template output

Struct

Let’s consider a struct with a collection of fields as declared inline:

Struct in go

The name of a field of the data struct, preceded by a period, such as .Name is the argument in the template. The result is the value of the field. Field invocations may be chained: .Field1.Field2 . Fields can also be evaluated on variables, including chaining: $x.Field1.Field2 . The following template shows the fields stored in variables and then evaluated in Actions.

Web template for struct in go

Web template output

Slice of structs

Let’s consider a slice of structs :

Slice to struct in go

We use a range to iterate over a slice. The value of the pipeline in Action must be an array (or slice). If the value of the length of the slice is zero, nothing is output; otherwise, dot (aka cursor) is set to the successive elements of the array, slice and Template is executed.

Web template for slice of structs

Different data structures in go can be combined to make useful templates.

A note on Conditionals in templates: It is also possible to write conditionals templates {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} like this. This gives us amazing abilities to generate dynamic content. If value of pipeline is empty (that is, false, 0, any

nil pointer or interface value, and any array, slice, map, or

string of length zero), T0 is executed else T1 is executed.

Function In templates

A function in a Go template we can be used if it is defined. By default, no functions are defined in the template, but the Funcs method on a template can be used to add function by creating mappings like this:

template.Must(template.New(“”).Funcs(fm).ParseFiles(“index.gohtml”))

Initialising a function for template in Go

To create a mapping from names to functions we need to use type FuncMap . Each function must have either a single return value or two return values of which the second has type error.

type FuncMap map[ string ]interface{}

On line:7, we have defined a mapping of function monthDayYear to name fdateMDY . Now this function can be used inside the template. Remember dot (aka cursor) holds the data provided to template.

Web template in go using function

These are various ways we can use templates in Go. I will publish how to use what we learned to build our own working web pages using nested templates. You can drop me hello with questions and feedback on twitter. Thanks!