Templating language

Apio uses Go’s  text/template  package for templates for speed, reliability and security.
The following is only a specific primer on the frequently used Go Templates. For an in-depth look into Go Templates, check the official  Go docs .
Go Templates provide an extremely simple template language that adheres to the belief that only the most basic of logic belongs in the template.

Basic Syntax

Go Templates are text files with the addition of variables and functions. Go Template variables and functions are accessible within  {{ }}  as below:
Text {{some go template call}} text {{ another call }}

The above example will fail to compile but shows the structure of template tags and the possibility to add extra padding spaces in side the tags.

Variables

variable could be a variable already existing in the current scope (like the  .Payload.OrderNumber  example below) or a custom variable (like the  $address  example in that same section).
{{ .Payload.OrderNumber }}
{{ $address := .Payload.address }}
{{ $address.firstname }}

Scope – the flow payload we are processing – has a  .Payload , and a  .Header  part.
Each Go Template gets a data object. In Apio, each template is passed a so-called  Bundle . In the below example,  .Payload.OrderNumber  is one of the elements accessible in that  Bundle .
With the  Bundle  being the default scope of a template, the  Payload.OrderNumber  element in current scope ( .  – "the dot") is accessible simply by the dot-prefix ( .Payload.OrderNumber ):
<OrderNumber>{{ .Payload.OrderNumber }}</OrderNumber>

Values can also be stored in custom variables and referenced later:
The custom variables need to be prefixed with  $ .
{{ $a := "Some value" }}
{{ $a }}

The example prints "Variable is APIO" if we have no data, and "Var is Data" if  .Payload.data  is not empty:
{{ $v := "APIO" }}
{{ if ne .Payload.data "" }} {{ $var = "not APIO" }}
{{ end }}
Variable is {{ $var }}

Methods and Fields are Accessed via dot Notation
Accessing the Page Parameter  bar  defined in a piece of content’s front matter.
{{ .Params.bar }}

Parentheses Can be Used to Group Items Together
{{ if or (isset .Params "alt") (isset .Params "caption") }} Caption {{ end }}


Functions

Go Templates only ship with a few basic functions but also provide a mechanism for applications to extend the original set.
Apio template functions provide additional functionality specific to building websites. Functions are called by using their name followed by the required parameters separated by spaces. Template functions can be added by opening a pull request to the developer team on  https://github.com/gpmd/gotemplate .
Parameters for functions are separated using spaces. The general syntax is:
{{ FUNCTION ARG1 ARG2 .. }}

The following example calls the  add  function with inputs of  1  and  2 :
{{ add 1 2 }}


Example 1: Adding Numbers

{{ add 1 2 }}
<!-- prints 3 -->


Example 2: Comparing Numbers

{{ lt 1 2 }}
<!-- prints true (i.e., since 1 is less than 2) -->

Note that both examples make use of Go Template’s  math functions .
There are more boolean operators than those listed in the  Go Template documentation .
Currently used in Apio:
"printf": printf, // built in
"range": range, // built in
"formatUKDate": formatUKDate, // 20/01/99 format
"ukdatetime": ukdatetime, // uk formatted date and time
"ukdate": ukdate, // uk formatted date
"unixtimestamp": timestamp, // unix timestamp
"nanotimestamp": nanotimestamp, // unix timestamp with nanoseconds
"dateFrom": dateFmtLayout,
"date": dateFmt, // "2017-03-31 19:59:11" | "06.01.02" => "17.03.31"
"timeformat": timeFormat,
"timeformatminus": timeFormatMinus,
"limit": limit,
"fixlen": fixlen, // fixlen 5 "10" => "10 "
"fixlenr": fixlenright, // fixlenr 5 "10" => " 10"
"sanitise": sanitise, // sanitise "a&b<c>" => "a&amp;b&lt;c&gt;"
"sanitize": sanitise, // same as sanitise
"last": last, // last (1,2,3) => 3
"reReplaceAll": reReplaceAll, // regex replace all
"replace": replace, // string replace
"match": regexp.MatchString, // string match => boolean
"title": strings.Title, // capitalised
"timestamp": timestamp, // long timestamp string
"datetime": datetime, // date and time as string
"json": asJSON, // structure to json string
"tojson": jsonDecode, // backward compatibility
"json_decode": jsonDecode,
"json_encode": jsonEncode,
"xml_decode": xmlDecode,
"xml_encode": xmlEncode,
"toUpper": strings.ToUpper, // string to uppercase
"upper": strings.ToUpper, // same as toUpper
"toLower": strings.ToLower, // string to lowercase
"lower": strings.ToLower, // same as toLower
"filter": filterPath,
"concat": concat, // concat "a" "b" => "ab"
"empty": empty, // empty [] => "", ["bah"] => "bah"
"int": toint, // int "0123" => 123
"float": tofloat, // float "0123.234" => 123.234
"ifthen": conditional, // ifthen "a" "b" => a, ifthen "" "b" => b
"elseifthen": notconditional, // elseifthen "a" "b" => b, elseifthen "" "b" => ""
"mapto": mapto, // mapto "a" "a:True|b:False" "|:" => True
"decimal": decimalFmt, // 3.1415 decimal 6,2 => 3.14
"item": item, // item "a:b" ":" 0 => a
"add": add, // add 1 2 => 3
"sub": subtract, // sub 1 2 => 1
"div": divide, // div 3 9 => 3
"mul": multiply, // mul 2 2 => 4
"var": newVariable, // var x 1
"explode": explode, // explode "a,b" "," => "a" "b"
"in_array": inArray, // in_array ["a","b"] "a" => true
"unique": unique, // unique [1,2,4,3,3,2] => [1,2,4,3]
"setItem": setItem,
"createMap": createMap,
"mkSlice": mkSlice,
"escape": escape,



Logic

Go Templates provide the most basic iteration and conditional logic.

Iteration

The Go Templates make heavy use of  range  to iterate over a maparray, or slice. The following are different examples of how to use  range .
Example 1: Using Context ( . )
{{ range $array }} {{ . }} <!-- The . represents an element in $array -->
{{ end }}

Example 2: Declaring a variable name for an array element’s value
{{ range $elem_val := $array }} {{ $elem_val }}
{{ end }}

Example 3: Declaring variable names for an array element’s index and value
For an array or slice, the first declared variable will map to each element’s index.
{{ range $elem_index, $elem_val := $array }} {{ $elem_index }} -- {{ $elem_val }}
{{ end }}

Example 4: Declaring variable names for a map element’s key and value
For a map, the first declared variable will map to each map element’s key.
{{ range $elem_key, $elem_val := $map }} {{ $elem_key }} -- {{ $elem_val }}
{{ end }}
See conditionals below for adding comma into a looped variable (like generating JSON output)

Conditionals

 if  else  with  or , and  and  provide the framework for handling conditional logic in Go Templates. Like  range , each statement is closed with an  {{ end }} .
Go Templates treat the following values as false:
 false  (boolean)
0 (integer)
any zero-length array, slice, map, or string
Example 1:  with 
It is common to write "if something exists, do this" kind of statements using  with .
 with  rebinds the context  .  within its scope (just like in  range ).
It skips the block if the variable is absent, or if it evaluates to "false" as explained above.
{{ with .Params.title }} <h4>{{ . }}</h4>
{{ end }}

Example 2:  with  ..  else 
Below snippet uses the "description" front-matter parameter’s value if set, else uses the default  .Summary   Page variable :
{{ with .Param "description" }} {{ . }}
{{ else }} {{ .Summary }}
{{ end }}

Example 3:  if 
An alternative (and a more verbose) way of writing  with  is using  if . Here, the  .  does not get rebinded.
Below example is "Example 1" rewritten using  if :
{{ if isset .Params "title" }} <h4>{{ index .Params "title" }}</h4>
{{ end }}

Example 4:  if  ..  else 
Below example is "Example 2" rewritten using  if  ..  else , and using  isset  function +  .Params  variable (different from the  .Param  function) instead:
{{ if (isset .Params "description") }} {{ index .Params "description" }}
{{ else }} {{ .Summary }}
{{ end }}

Example 5:  if  ..  else if  ..  else 
Unlike  with  if  can contain  else if  clauses too.
{{ if (isset .Params "description") }} {{ index .Params "description" }}
{{ else if (isset .Params "summary") }} {{ index .Params "summary" }}
{{ else }} {{ .Summary }}
{{ end }}

Example 6:  and  &  or 
{{ if (and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")) }}


Adding comma in a loop ignoring the first occurance:
[
{{range $i, $value := .Payload}}
{{if $i}},{{end -}}
"{{$value}}"
{{end}}
]
The trick above is that $i will go from 0 to  {{len .Payload}} , on 0 we don't output a comma (before the first item).

Pipes

One of the most powerful components of Go Templates is the ability to stack actions one after another. This is done by using pipes. Borrowed from Unix pipes, the concept is simple: each pipeline’s output becomes the input of the following pipe.
Because of the very simple syntax of Go Templates, the pipe is essential to being able to chain together function calls. One limitation of the pipes is that they can only work with a single value and that value becomes the last parameter of the next pipeline.
A few simple examples should help convey how to use the pipe.

Example 1:  shuffle 

The following two examples are functionally the same:
{{ shuffle (seq 1 5) }}

{{ (seq 1 5) | shuffle }}


Example 2:  index 

The following accesses the page parameter called "disqus_url" and escapes the HTML. This example also uses the   index  function , which is built into Go Templates:
{{ index .Params "disqus_url" | html }}


Example 3:  or  with  isset 

{{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr") }}
Stuff Here
{{ end }}

Could be rewritten as
{{ if isset .Params "caption" | or isset .Params "title" | or isset .Params "attr" }}
Stuff Here
{{ end }}


Example 4: Internet Explorer Conditional Comments

By default, Go Templates remove HTML comments from output. This has the unfortunate side effect of removing Internet Explorer conditional comments. As a workaround, use something like this:
{{ "<!--[if lt IE 9]>" | safeHTML }} <script src="html5shiv.js"></script>
{{ "<![endif]-->" | safeHTML }}

Alternatively, you can use the backtick (```) to quote the IE conditional comments, avoiding the tedious task of escaping every double quotes ( " ) inside, as demonstrated in the  examples  in the Go text/template documentation:
{{ `<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->` | safeHTML }}


Context (aka "the dot")

The most easily overlooked concept to understand about Go Templates is that  {{ . }}  always refers to the current context.
In the top level of your template, this will be the data set made available to it.
Inside of an iteration, however, it will have the value of the current item in the loop; i.e.,  {{ . }}  will no longer refer to the data available to the entire packet, not advisable though.


1. Define a Variable Independent of Context

The following shows how to define a variable independent of the context.
{{ $o := .Payload.order }}
<ul>
{{ range .Payload.items }} <li> <a href="/tags/{{ . | urlize }}">{{ .sku }}</a> - {{ $order.customer.priceband }} {{.product_name}} </li>
{{ end }}
</ul>

Notice how once we have entered the loop (i.e.  range ), the value of  {{ . }}  has changed. We have defined a variable outside of the loop ( {{$title}} ) that we’ve assigned a value so that we have access to the value from within the loop as well.

2. Use  $.  to Access the Global Context

 $  has special significance in your templates.  $  is set to the starting value of  .  ("the dot") by default. This is a  documented feature of Go text/template . This means you have access to the global context from anywhere. Here is an equivalent example of the preceding code block but now using  $  to grab  .Site.Title  from the global context:
range-through-tags-w-global.html
<ul>
{{ range .Params.tags }} <li> <a href="/tags/{{ . | urlize }}">{{ . }}</a> - {{ $.Site.Title }} </li>
{{ end }}
</ul>

The built-in magic of  $  would cease to work if someone were to mischievously redefine the special character; e.g.  {{ $ := .Site }} Don’t do it. You may, of course, recover from this mischief by using  {{ $ := . }}  in a global context to reset  $  to its default value.

Whitespace

Go 1.6 and above includes the ability to trim the whitespace from either side of a Go tag by including a hyphen ( - ) and space immediately beside the corresponding  {{  or  }}  delimiter.
For instance, the following Go Template will include the newlines and horizontal tab in its HTML output:
<div> {{ .Title }}
</div>

Which will output:
<div> Hello, World!
</div>

Leveraging the  -  in the following example will remove the extra white space surrounding the  .Title  variable and remove the newline:
<div> {{- .Title -}}
</div>

Which then outputs:
<div>Hello, World!</div>

Go considers the following characters whitespace:
space
horizontal tab
carriage return
newline

Comments

In order to keep your templates organized and share information throughout your team, you may want to add comments to your templates. There are two ways to do that in Apio.

Go Templates comments

Go Templates support  {{/*  and  */}}  to open and close a comment block. Nothing within that block will be rendered.
For example:
Bonsoir, {{/* {{ add 0 + 2 }} */}}Eliott.

Will render  Bonsoir, Eliott. , and not care about the syntax error ( add 0 + 2 ) in the comment block.

Apio Interface Environment variables

Apio provides the option of passing environment variables to your template through your app environment variables (accessible in the build list screen of your app) . You can define any key-value pairs, where both key and value are string.
As an example in environment variables screen let's define a variable called  api_url  with value  https://cloud.apio.rocks/api/CA56G90L  (just an example), to use this as a prefix for any API endpoint in the URL field for a HTTP step we can type:
=<.api_url>=/v1/orders
The resulting URL will be  https://cloud.apio.rocks/api/CA56G90L/v1/orders  while running the app. The =< and >= are a special delimiter handles, the dot before api_url will tell the templating language that we are using a value from the provided environment variables.
In theory we could use built in functions inside =< >= tags but normally there is no need for this and makes checking for environment variables programmatically harder, so any other syntax is discouraged.

Template Debugging

You can use Go templates’  printf  function to debug your Apio templates. These snippets provide a quick and easy visualization of the variables available to you in different contexts.
Here are some snippets you can add to your template to answer some common questions.
These snippets use the  printf  function available in all Go templates. This function is an alias to the Go function,  fmt.Printf .

What Variables are available in Payload?

In theory ou can use the template syntax  . , to get the top-level context from anywhere in your template. This will print out all the values under,  .Payload  with go type declaration syntax.
{{ printf "%#v" .Payload }}


Further reading