Templates are essentially static text files that are used to create dynamic content by replacing variables with actual values and transforms into an HTML and Text file. This approach makes it easier to design an HTML page or a text file. Golang uses the same principle to generate dynamic webpages.

Templates In Go

Go web templates allow us to serve personalized results to users. Go templates are simple but powerful methods to customize the output by applying them to a data structure (Inputs). Golang standard library has two packages with the same interface having subtle web-specific differences in the latter like encoding script tags to prevent them from running, parsing maps as JSON in view, and more. text/templates This package implements data-driven templates for generating text output safe against code injection. html/templates This package implements data-driven templates for generating HTML output safe against code injection. It provides the same interface as a package text/template and should be used instead of text/template whenever the output is HTML.

Template Naming

Go templating does not have any defined file extension. One of the most popular extensions is .tmpl supported by vim-go and referenced in the text/template godocs. The extension .gohtml supports syntax highlighting in both Atom and Go Sublime editors. While the extension is not important it is still good to be consistent within a project for clarity.

Parsing Templates

Single
Get the template using provided string and store it in the t.
t, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
Get the template at the filename and store it in t.
t, err := template.Parse(filename)
Multiple
Parse and stores all templates for provided list of filenames
t, err := template.ParseFiles(filenames)
Find all templates matching the pattern and store the templates.
t, err := template.ParseGlob(pattern)
Must
Must is a helper that wraps a call to a function returning (*Template, error) and panics if the error is non-nil.
t := template.Must(template.New("name").Parse("text"))

Executing Templates

Once a template is parsed, it can be executed safely in parallel, although if parallel executions share a Writer the output may be interleaved. Once execution completes the content of the parsed template (t) will be written to the io.Writer. Input Data is an interface passed to the template that will be useable by the template to replace variables with actual values. There are two options to execute them.
Single
t.Execute(io.Writer, data) will be used for single template execution.
Named
t.ExecuteTemplate(io.Writer, name, data) will be used for executing a specific template with the name.

Variables

The template package allows you to define and use variables. A template variable can be a boolean, string, character, integer, floating-point,] imaginary, or complex constant in Go syntax.
The Dot (.) Operator
{{ . }} Input Data passed to the template can be accessed using a dot.
Fields
{{ .FieldName }} If the data is a complex type then its fields can be accessed using the dot.
Nested Fields
{{ .Struct.StructTwo.Field }} Dots can be chained together if the data contains multiple complex structures.
Definition
Data passed to the template can also be saved in a variable and used throughout the template {{ $value := . }}. We use the $value to create a variable then initialize it with the value passed to the template. To use the variable we call it in the template with {{ $value }}.

Actions

Remove White Space
By default, all text between actions is copied verbatim when the template is executed as a result it can add a various number of whitespaces. We can change the template code to remove additional whitespaces or make use (Minus) symbol to remove leading and trilling spaces. {{- All trailing white space is trimmed from the immediately preceding text -}} All leading white space is trimmed from the immediately following text
Comments
{{/* A comment */}} A comment is discarded by the template executor. Comments may contain newlines. Comments do not nest and must start and end at the delimiters
Pipeline
Unix users should be familiar with the pipe operator, like ls | grep “test”. This command filters files and only shows those that contain the world test. Similar to that go template supports pipes. Anything in the {{ }} is considered a data pipeline. {{ . | html }} is a pipeline to escape input data into HTML to avoid any vulnerable XSS attack.
If / Else
Unlike any other language go template allows us to check values using the If / else block. The empty values for a variable are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. for example:
{{if pipeline}} Exists {{end}} If the value of the pipeline is empty, no output is generated; otherwise, Exists is printed.
{{if pipeline}} Exists {{else}} Not Available {{end}} If the value of the pipeline is empty, Not Available is printed; otherwise, Exists is printed.
Dot is unaffected.
Range
Unlike any other language, Go templates allows us to iterate through a collection of values using the range. The value of the pipeline must be an array, slice, map, or channel. If the value is a map and the keys are of the basic type with a defined order, the elements will be visited in sorted key order.
{{range pipeline }} T1 {{end}} If the value of the pipeline has length zero, nothing is output; otherwise, the dot is set to the successive elements of the array, slice, or map, and T1 is executed.
{{range pipeline }} T1 {{else}} T0 {{end}} If the value of the pipeline has length zero, the dot is unaffected and T0 is executed; otherwise, the dot is set to the successive elements of the array, slice, or map and T1 is executed.
With
{{with pipeline}} T1 {{end}} If the value of the pipeline is empty, no output is generated; otherwise, dot is set to the value of the pipeline, and T1 is executed.
{{with pipeline}} T1 {{else}} T0 {{end}} If the value of the pipeline is empty, the dot is unaffected and T0 is executed; otherwise, the dot is set to the value of the pipeline and T1 is executed.

Functions

{{ if and .User .User.Admin }} Go template allows us to call different functions to evaluate input data and generate the required output.
Built-In Functions
There are a couple of built-in functions support is available outofbox in the go template package.
Comparison Functions
Helper Functions
Calling Functions
Comparison Functions
  • eq returns the Boolean truth of arg1 == arg2
  • ne returns the Boolean truth of arg1 != arg2
  • lt returns the Boolean truth of arg1 < arg2
  • le returns the Boolean truth of arg1 <= arg2
  • gt returns the Boolean truth of arg1 > arg2
  • ge returns the Boolean truth of arg1 >= arg2
  • and returns the Boolean AND of its arguments by returning the first empty argument or the last argument.
  • or returns the Boolean OR of its arguments by returning the first non-empty argument or the last argument
  • not returns the Boolean negation of its single argument.
Helper Functions
  • print an alias for fmt.Sprint
  • printf an alias for fmt.Sprintf
  • println an alias for fmt.Sprintln
  • len returns the integer length of its argument.
  • index returns the result of indexing its first argument by the following arguments. Each indexed item must be a map, slice, or array.
  • html returns the escaped HTML equivalent of the textual representation of its arguments.
  • slice returns the result of slicing its first argument by the remaining arguments. The first argument must be a string, slice, or array.
  • js returns the escaped JavaScript equivalent of the textual representation of its arguments.
  • urlquery returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query.
Calling Functions
Go templates support the execution of custom functions defined by the user such as
Templates can call methods (Struct Function) of objects in the template to return data.
{{ if .User.HasPermission "feature-a" }}
Go template allows us to call function variable on Input Data, to achieve this we must change the template call function variable using call keyword.
{{ if (call .User.HasPermission "feature-b") }}
Another way to call functions is to create custom global function with template.FuncMap. This method creates global methods that can be used throughout the entire application. FuncMap has type map[string]interface{} mapping strings to functions. The mapped functions must have either a single return value, or two return values where the second has type error.
{{ if hasPermission .User "feature-a" }}

Encoding & HTML

html/template package uses code context to encode any characters that need to be encoded to be rendered correctly. Type template.HTML should be used consciously this can cause a vulnerable XSS attack if user input is dangerous (contains vulnerable XSS attack). For example the < and > in "<h1>Title</h1>" will be encoded as amp;lt;h1&gt;Title&lt;/h1&gt;. Type template.HTML can be used to skip encoding by telling Go the string is safe. Template.HTML("<h1>A Safe header</h1>") will then be <h1>A Safe header</h1>

Nested Templates & Layouts

Unlike any web application frameworks, certain part of templates can be reused across other templates, like header and footer. Rather than updating each template separately we can use a nested template that all other templates can use.
master = `Names: {{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
overlay = `{{define "list"}} {{join . ", "}}{{end}}`

Example

Template

Final Thought

In this section we learnt how to combine dynamic input data with templates using techniques including data in variables, loops, template functions, nested templates, and HTML escaping.