Go Template

There is no template engine on Go or GoLang. Because the language itself already supports it without any third party.

A template processor (also known as a template engine or template parser) is software designed to combine templates with a data model to produce result documents. The language that the templates are written in is known as a template language or templating language.

There are many template engines for many programming languages:

...and, there is none for Go.

How cool it is. Go is so simple and modern. Go was born with a template engine feature. So, we don't need any third party or alternative. Let me bring how to work with the Go template in a single article here.

There are built-in packages named "templates" under "html" and "text" packages. You can check them here, https://golang.org/pkg/:

Templates are executed by applying them to a data structure. Annotations in the template refer to elements of the data structure (typically a field of a struct or a key in a map) to control execution and derive values to be displayed. Execution of the template walks the structure and sets the cursor, represented by a period '.' and called "dot", to the value at the current location in the structure as execution proceeds.

Here is an example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    {{.}}
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

Here is the Go code for that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
    "bytes"
    "io"
    "log"
    "net/http"
    "text/template"
)

var tmpl *template.Template

func init() {
    tmpl = template.Must(template.ParseFiles("hello.gohtml"))
}

func main() {
    var response bytes.Buffer
    if err := tmpl.Execute(&response, `<script>alert("Hello World!")</script>`); err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, response.String())
    })
    http.ListenAndServe(":80", nil)
}

I tried to print out inline JavaScript in the head. Of course, it is not safe to against code injection and can cause Cross-Site Scripting (XSS). The safe one is to use from "html" package.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<pre>{{.}}</pre>
</body>
</html>

I tried to print out the raw HTML tag, script, into the pre tag. The Go code is the same as above. We just need to change the built-in package from "text/template" to "html/template".

Go template can be inside of files or string variables. We can use any file extension for files that contain only strings of the Go template. The most common file extensions are .gohtml, .tmpl, or .tpl.

Variable

Here is an example of using variables inside the Go template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{{$title := .}}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{$title}}</title>
</head>
<body>
<h1>{{$title}}</h1>
</body>
</html>

Range

We can do looping using a slice or map.

Slice

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Range - Slice</title>
</head>
<body>
<h1>Range - Slice</h1>
<ol>
    {{range .}}
    <li>{{.}}</li>
    {{end}}
</ol>
</body>
</html>

Map

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Range - Map</title>
</head>
<body>
<h1>Range - Map</h1>
<ul>
    {{range $key, $val := .}}
    <li>{{$key}}: {{$val}}</li>
    {{end}}
</ul>
</body>
</html>

Struct

Go template can only pass a struct.

Simple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Struct</title>
</head>
<body>
<h1>Struct</h1>
<p>His name is {{.Name}}. His age is {{.Age}}.</p>
</body>
</html>

Complex

Here is an example if we want to pass a slice or map inside a struct.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Struct - Slice - Map</title>
</head>
<body>
<h1>Struct - Slice - Map</h1>
<h2>Names</h2>
<ol>
    {{range .Names}}
    <li>{{.}}</li>
    {{end}}
</ol>
<h2>Jobs</h2>
<ul>
    {{range $key, $val := .Jobs}}
    <li>{{$key}}: {{$val}}</li>
    {{end}}
</ul>
</body>
</html>

Functions

We can pass functions into the Go template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Functions</title>
</head>
<body>
<h1>Functions</h1>
<h2>Title</h2>
<ol>
    {{range .Names}}
    <li>{{title .}}</li>
    {{end}}
</ol>
<h2>Fibonacci</h2>
<ul>
    {{range .Numbers}}
    <li>{{.}}: {{fibonacci .}}</li>
    {{end}}
</ul>
</body>
</html>

Here is the Go code for that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
    "bytes"
    "io"
    "log"
    "math"
    "net/http"
    "strings"
    "text/template"
)

func fibonacci(number int) int {
    return int(math.Round(math.Pow(float64((1+math.Sqrt(5))/2), float64(number)) / math.Sqrt(5)))
}

var tmpl *template.Template

var functions = template.FuncMap{
    "title":     strings.Title,
    "fibonacci": fibonacci,
}

func init() {
    tmpl = template.Must(template.New("tmpl.gohtml").Funcs(functions).ParseFiles("tmpl.gohtml"))
}

func main() {
    var response bytes.Buffer
    data := struct {
        Names   []string
        Numbers []int
    }{
        []string{"john doe", "john cena", "harry potter"},
        []int{1, 3, 5, 7, 9},
    }
    if err := tmpl.Execute(&response, data); err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, response.String())
    })
    http.ListenAndServe(":80", nil)
}

We created a Fibonacci function and we use a built-in function Title from the strings built-in package.

Pipeline

Data passing through multiple functions is called a pipeline.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Functions Pipeline</title>
</head>
<body>
<h1>Functions Pipeline</h1>
<ul>
    <li>{{.}}</li>
    <li>{{. | one}}</li>
    <li>{{. | one | two}}</li>
</ul>
</body>
</html>

Global

There are also global functions from the Go template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Global Functions</title>
</head>
<body>
<h1>Global Functions</h1>
<ul>
    <li>{{index .Numbers 2}}</li>
    <li>{{index .Numbers 1}}</li>
    <li>{{index .Numbers 0}}</li>
</ul>
<p>Length: {{len .Numbers}}</p>
<p>Raw: {{print .Numbers}}</p>
<h2>Conditions</h2>
{{if lt .Arg1 .Arg2}}
<p>{{.Arg1}} is less than {{.Arg2}}.</p>
{{end}}
{{if gt .Arg2 .Arg1}}
<p>{{.Arg2}} is greater than {{.Arg1}}.</p>
{{end}}
{{if eq .Arg1 .Arg3}}
<p>{{.Arg1}} is equal to {{.Arg3}}.</p>
{{end}}
</body>
</html>

Nested

We can make multiple Go templates then combine one into a single Go template.

1
2
3
4
5
6
7
8
9
{{define "header"}}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{.}}</title>
</head>
<body>
{{end}}
1
2
3
4
{{define "footer"}}
</body>
</html>
{{end}}
1
2
3
{{template "header" .}}
<h1>{{ page.dot }}</h1>
{{template "footer"}}

Closing

Those are examples of the Go template. For full reference, you can go to the documentation of the text and HTML template packages. The source code for this article is at https://github.com/aristorinjuang/go-templates.

References

Related Articles

Comments