Templating in programming is common. Over the years, some well known languages have emerged and been adapted by millions.
While some of these templating languages have very specialized use cases, others are excellent general purpose languages. Jinja2 for example has been adopted by Ansible to create dynamic configuration files.
Why you should learn go template syntax
Many modern tools are written in go and allow using templates. The 2 major use cases are dynamic configuration files and formatting output.
Some projects that use go templates are:
- Docker
- Kubernetes
- Helm
- Hugo
- Nomad
- Consul-template
- Vault
- Levant
- Packer
That means when working with modern DevOps tools, sooner or later you will encounter go templates. While there is often times a way around using them, they can enhance the overall workflow drastically.
Getting Started
I would recommend reading go template syntax from the nomad docs.
I have created my own project that uses go templates. Since it renders any JSON input, it can be a useful learning tool.
If you want, you can install it with go get
or use the docker image
from docker hub.
jpipe
Render json with go templates from the command line
Docker
curl --silent https://jsonplaceholder.typicode.com/users/1 \
| docker run --interactive bluebrown/jpipe \
--newline '{{.name}}'
Local
go get github.com/bluebrown/jpipe
Usage
The templates are executed with the text/template package. That means so they are not injection safe while providing greater flexibility for the user. don't execute untrusted templates!
$ echo '{"place": "bar"}' | jpipe 'lets go to the {{.place}}!'
lets go to the bar!
The template is either read from the first positional argument or from a path specified via --template
or -t
flag.
echo '{"place": "bar"}' | jpipe --template path/to/template
The json input is read from pipe or redirection.
jpipe < path/to/input.json
curl localhost | jpipe
Flags
-n
-newline
print new line at the end
-t string
-template string
alternative way to specify template
Sprig
Sprig functions have been added to provide more…
It takes JSON as input from pipe or redirection and passes the data to a template that is either specified from a file or as positional argument.
By default, the data is rendered in its raw form. It can be an object or array which will become either a map or a slice.
Basic:
# object
$ echo '{ "data": "foo" }' | jpipe
map[data:foo]
# array
$ echo '[1,2]' | jpipe
[1 2]
Passing a template as positional argument:
# object
$ echo '{ "data": "foo" }' | jpipe '{{ .data }}'
foo
# array
$ echo '[1,2]' | jpipe '{{ index . 1 }}'
2
Advanced Syntax
Apart from the basic syntax covered by the nomad docs, below is some more info about templates.
Context
It is important to keep in mind that the .
always refers to the current context. The default template actually looks like this:
{{ . }}
Function Call
In go template function are called the same way they are in normal .go files but the parenthesis and commas are stripped away.
So the normal println(item)
becomes {{ println . }}
. If you have more than 1 argument, then you just add those without a comma.
{{ printf "the size is %f\n" . }}
Iteration
Often times we want to range over an array or even the keys and values of a map.
When iterating over data, the .
will become the item of the current iteration.
{{ range . }} ... {{ end }}'
You can also get the index by assigning it to a variable.
{{ $index, $element := range . }} ... {{ end }}
To iterate over the keys and values of an object, the following syntax is used.
{{ range $key, $val := . }} ... {{ end }}
The Index Function
Sometimes, we need to look up an element in an array by index. The index
function takes a slice as first argument and the index of the element to return as second argument.
{{ index .mySlice 2 }}
It is also possible to assign the returned element to a variable and use it somewhere else in the template.
{{ $item := index .mySlice 2 }}{{ $item.title }}
The index function can also lookup keys in a map.
{{ index .myMap "some-key" }}
Example
You can view this example on github.
Below is another example rendering some articles with dev.to liquid tags.
$ curl -s "https://dev.to/api/articles?username=codingsafari&per_page=3" > posts.json
$ jpipe '### {{ println "Posts\n" }}{{range .}}{{ printf "{%% link %s %%}\n" .url }}{{end}}' < posts.json
Raw Output
### Posts
{% link https://dev.to/codingsafari/building-production-grade-container-images-3nhg %}
{% link https://dev.to/codingsafari/advanced-entrypoint-techniques-for-docker-container-3dc %}
{% link https://dev.to/codingsafari/kubernetes-ingress-controller-gpe %}
Rendered Markdown
Posts
Building Production Grade Container Images
Nico Braun ・ Jun 28 ・ 7 min read
Discussion (0)