Notification templates

Notification templates are a way of generating notifications: by defining a title and a content templates, they will be filled up with the data provided through the API endpoints.

Notify17 notification templates use the well known Go templates syntax, with the request payload being the context of the template.

You can find extensive documentation, which applies to all the basic syntax of the templates, at https://golang.org/pkg/text/template/ .

Basic example

A notification template can be created in the Notification templates  page.

To trigger a notification using a template, you can send a cURL  request containing your payload (JSON/Form):

curl "https://hook.notify17.net/api/template/TEMPLATE_API_KEY?name=Mr.%20Anderson"
curl -X POST \
  "https://hook.notify17.net/api/template/TEMPLATE_API_KEY" \
  -F name="Mr. Anderson"
curl -X POST \
  "https://hook.notify17.net/api/template/TEMPLATE_API_KEY" \
   --header "Content-Type: application/json" \
   --data "{\"name\":\"Mr. Anderson\"}"

The basic usage of a template is:

Template Payload
This is a greeting!

---

Hello {{ .name }}!
{
  "name": "Mr. Anderson"
}
Rendered
This is a greeting!

---

Hello Mr. Anderson!

Access payload variables

Template Payload
Hello {{ .name }}!

---

You live in {{ .address.city }}.
{
  "name": "John",
  "address": {
    "city": "Toronto"
  }
}
Rendered
Hello John!

---

You live in Toronto.

Delete all the whitespaces!

The little dashes (-) you see around are used to delete the whitespaces and newlines between where they’re used and:

  • {{- <- The word closest to the left of the template block
  • -}} <- The word closest to the right of the template block
Template Payload
Hello    {{ .name }}!

Hello    {{- .name }}!
{
    "name": "General Kenobi"
}
Rendered
Hello    General Kenobi!

HelloGeneral Kenobi!

NOTE: By default Notify17 will remove, from generated notifications, groups of 3+ newlines and collapse them into 2 newlines, to improve content readability.

Delete all the whitespaces!

Comments

You can add a comment using the notation {{/* This is a comment! */}}. Comments will not be rendered in the notification.

To remove whitespaces and newlines around comments, use the {{- /* and */ -}} tags.

Template
Line 1

{{/*
    We're doing lots of stuff here, so we want some comments.
    
    This is a multiline comment.
*/}}

Line 2

{{/* Single line comment with white space clearing*/ -}}
 
Line 3
Rendered
Line 1

Line 2

Line 3

Conditionals

Template Payload
{{ if eq .success true -}}
Success!
{{- else -}}
Failed!
{{- end }}

{{ if gt .value 5 -}}
The value is bigger than 5!
{{- else -}}
What a small value!
{{- end }}
{
  "success": true,
  "value": 10.1
}
Rendered
Success!

The value is bigger than 5!

Available comparison functions:

  • eq .A .B -> A == B (also existsAndEq)
  • ne .A .B -> A != B (also existsAndNE)
  • lt .A .B -> A < B (also existsAndLT)
  • le .A .B -> A <= B (also existsAndLE)
  • gt .A .B -> A > B (also existsAndGT)
  • ge .A .B -> A >= B (also existsAndGE)

existsAnd- variants

A generic exists functions is available to test if a field is present or not.

The other existsAnd- comparison variants are quite useful when dealing with trigger conditions, whenever you want to check if a field exists before comparing it.

Template Payload
{{ if not (exists .hello) }}
Oh, hello does not exist!
{{ end }}

{{ if existsAndEq .value .invalidOne }}
Wow, really?
{{ else }}
Oh, some values did not exist!
{{ end }}

{{ if existsAndEq .value 10.1 }}
Yay!
{{ end }}
{
  "value": 10.1
}
Rendered
Oh, hello does not exist!

Oh, some values did not exist!

Yay!

Why do we need these variants?

These variants were introduced to solve the problem “how do I trigger a template only if this field exists and is not 0?”.

One may think it is possible to check if a field (e.g. .code) exists and is not 0 by using the following template:

{{ if and (.code) (ne .code 0) }}
It exists!
{{ end }}

The problem with the previous template is that the second argument of the conditional ((ne .code 0)) is evaluated BEFORE the actual and, triggering a comparison error (nil vs 0). Therefore, you need a wrapper to the conditional, that returns false whenever any of the arguments are null or do not exist.

Arrays

Template Payload
Second element: {{ index .myArray 1 }}
{
  "myArray": [
     "I'm first!",
     "I'm second :("
  ]
}
Rendered
Second element: I'm second :(

Loops

Template Payload
The number 3 is perfect:

{{ range $entry := .entries -}}
* {{ $entry.name }}
{{ end }}
{
  "entries": [
    {"name": "Doom 3"},
    {"name": "Half-Life 3 😈"},
    {"name": "Far Cry 3"}
  ]
}
Rendered
The number 3 is perfect:

* Doom 3
* Half-Life 3 😈
* Far Cry 3
Template Payload
Ids:

{{ range $idx, $field := .array -}}
- {{ $field }} at idx {{ $idx }}
{{ end }}
{
  "array": [
    "id-1",
    "id-2",
    "id-3"
  ]
}
Rendered
Ids:

- id-1 at idx 0
- id-2 at idx 1
- id-3 at idx 2
Template Payload
Ids:

{{ range $key, $value := .map -}}
- {{ printf "%s: %v" $key $value }}
{{ end }}
{
  "map": {
    "a": 1,
    "b": 25,
    "c": 10
  }
}
Rendered
Ids:

- a: 1
- b: 25
- c: 10

Trigger conditions

If you want your notification templates to generate notifications ONLY if certain conditions are met (e.g. the payload variable status is alerting), you can use the Trigger condition field.

This field can contain an if-template (an expression that you would place inside a if block), which gets checked whenever the notification template is used through the templated notifications API.

Examples:

  • Trigger only if status is alerting:

    eq .status "alerting"

  • Trigger only if the decoded base64 value of signature is report/1234:

    eq (b64dec .signature) "report/1234"

  • Trigger only if timestamp (unix time) is not older than 1 hour (e.g. to prevent old useless/delayed notifications from popping up):

    (parseUnixTime .timestamp).After (now.Add (parseDuration "-1h"))

    Let’s break this one down:

    • parseUnixTime .timestamp converts the payload field timestamp to a time.Time  element.
    • parseDuration "-1h" converts the literal -1h to a time.Duration  element.
    • now.Add (parseDuration "-1h") subtracts 1 hour from the current time.
    • .After  is the actual check for (now.Add (parseDuration "-1h")) date to be after (parseUnixTime .timestamp).

You can find more examples in the Conditionals section.

Functions

Notify17 has a set of embedded functions that you can use to process the notification payloads, mainly based on the open-source library Sprig (v3.1.0)  (you may be familiar with these functions if you use Helm  to deploy resources in Kubernetes).

Dump

Function nameArgsOutputExample
dumpobjHuman friendly YAML representation of obj
{{ dump (split " " "a b c") }}
Result:
_0: a
_1: b
_2: c
toStringobjHuman friendly representation of obj
{{ toString (split " " "a b c") }}
Result: map[_0:a _1:b _2:c]

Dates

Note: $dateVar variable refers to November 16, 2004 - 00:12:34.567 UTC .

Note: $durationVar variable refers to 30 minutes 45 seconds 96 milliseconds .

Function nameArgsOutputExample
agodateHow many seconds have elapsed since the provided date
{{ ago $dateVar }}
Result: 138990h45m28s
dateformat, dateFormat date to string using format (UTC)
{{ date "2006/01/02 15:04:05" $dateVar }}
Result: 2004/11/16 00:12:34
dateInZoneformat, date, timeZoneFormat date to string using format, interpreting date within timeZone
{{ dateInZone "2006/01/02 15:04:05" $dateVar "America/New_York" }}
Result: 2004/11/15 19:12:34
dateISOdateFormat date to string using ISO 8601 format  (UTC timezone)
{{ dateISO $dateVar }}
Result: 2004-11-16T00:12:34.567Z
dateModifyduration, datedate + duration. If duration is a non valid string, returns the date
{{ dateISO (dateModify "-2h" $dateVar) }}
Result: 2004-11-15T22:12:34.567Z
durationsecondsCreates a duration object from seconds
{{ duration "3600" }}, {{ duration 67 }}
Result: 1h0m0s, 0s
durationRounddurationRounds duration down to the closest biggest time interval
{{ durationRound "32h15m28s" }}, {{ durationRound "15m28s" }}
Result: 1d, 15m
htmlDatedatedate formatted as YYYY-MM-DD
{{ htmlDate $dateVar }}
Result: 2004-11-16
htmlDateInZonedate, timeZonedate formatted as YYYY-MM-DD, interpreting date within timeZone
{{ htmlDateInZone $dateVar "America/New_York" }}
Result: 2004-11-15
humanDurationdurationPrints duration in a verbose human-friendly format
{{ humanDuration $durationVar }}
Result: 30 minutes 45 seconds 96 milliseconds
humanDurationResresolution, durationPrints duration in a verbose human-friendly format, but outputting only first resolution elements
{{ humanDurationRes 2 $durationVar }}
Result: 30 minutes 45 seconds
mustDateModifyduration, datedate + duration. If duration is a non valid string, fails to generate the notification
{{ dateISO (mustDateModify "-2h" $dateVar) }}
Result: 2004-11-15T22:12:34.567Z
mustToDateformat, valueParses value using format  into a date object. On bad parsing, fails to generate the notification
{{ htmlDate (mustToDate "January 02, 2006" "November 16, 2004") }}
Result: 2004-11-16
nowThe current date as object, to be used in conjunction with other date functions
{{ dateISO now }}
Result: 2020-09-24T06:58:02.644Z
parseDurationtextReturns a duration from the string text, to be used in conjunction with other date functions
{{ $dateVar.Add (parseDuration "-23h") }}
Result: 2004-11-15 01:12:34.567 +0000 UTC
parseUnixTimesecondsReturns a date from unix-time seconds
{{ parseUnixTime 1574402832 }}
Result: 2019-11-22 06:07:12 +0000 UTC
parseUnixTimeMsmillisecondsReturns a date from unix-time milliseconds
{{ parseUnixTimeMs 1574402832123 }}
Result: 2019-11-22 06:07:12.123 +0000 UTC
toDateformat, valueParses value using format  into a date object. On bad parsing, returns a void date
{{ toDate "January 02, 2006" "November 16, 2004" }}
Result: 2004-11-16 00:00:00 +0200 EET
unixEpochdatedate in unix-time seconds
{{ unixEpoch $dateVar }}
Result: 1100563954

Strings

Function nameArgsOutputExample
abbrevmaxWidth, textLimits text + to maxWidth
{{ abbrev 5 "Do not go gentle into that good night" }}
Result: Do...
abbrevbothoffset, maxWidth, textLimits text + to maxWidth, also ellipsizing () the left side by offset
{{ abbrevboth 6 25 "Do not go gentle into that good night" }}
Result: ... go gentle into tha...
camelcasetextCamel-cases text
{{ camelcase "_begin_the_awakening" }}
Result: _BeginTheAwakening
catstr1, str2, ...Concatenates all args
{{ cat "hello" "world" "!" }}
Result: hello world !
containsstr, textTrue if text contains str
{{ if contains "oh" "Helloh!" }}Yes!{{ end }}
Result: Yes!
hasPrefixstr, textTrue if text starts with str
{{ if hasPrefix "He" "Helloh!" }}Yes!{{ end }}
Result: Yes!
hasSuffixstr, textTrue if text ends with str
{{ if hasSuffix "h!" "Helloh!" }}Yes!{{ end }}
Result: Yes!
indentspaces, textIndent text with desired number of spaces
{{ indent 4 "hello" }}
Result: hello
initialstextExtracts the initial letters from each word in text
{{ initials "Carl Johnson" }}
Result: CJ
kebabcasetextKebab-cases text
{{ kebabcase "beginTheAwakening" }}
Result: begin-the-awakening
localIptextTrue if text is an IPv4/v6 address in the local ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
{{ localIp "192.168.5.103" }}
Result: true
lowertextLower-cases text
{{ lower "Yes sir, Mister Johnson" }}
Result: yes sir, mister johnson
nindentspaces, textIndent text with desired number of spaces and prepend a newline
{{ nindent 4 "hello" }}
Result: hello
nospacetextRemoves all whitespaces from text
{{ nospace "Yes sir, Mister Johnson" }}
Result: Yessir,MisterJohnson
pluralone, many, countIf count > 1, returns many, otherwise returns one
{{ plural "Apple" "Apples" 3 }}
Result: Apples
quotestr1, str2, ...Wraps all args with "
{{ quote "Ohoh! \" some characters ' here" }}
Result: "Ohoh! \" some characters ' here"
randAlphalengthRandom alpha string with length characters
{{ randAlpha 14 }}
Result: QelqCFHgSaAMHX
randAlphaNumlengthRandom alpha-numeric string with length characters
{{ randAlphaNum 15 }}
Result: KT3LSW616NaUiBb
randAsciilengthRandom ASCII string with length characters
{{ randAscii 13 }}
Result: LM9fe)?BwW2_!
randNumericlengthRandom numeric string with length characters
{{ randNumeric 12 }}
Result: 211122964340
repeatcount, textRepeats text count times
{{ repeat 3 "Oh " }}!
Result: Oh Oh Oh !
replaceold, new, textReplaces all occurrences of old with new in text
{{ replace "Ap" "Pr" "Apple, say \"Apple\"!"  }}
Result: Prple, say "Prple"!
shuffletextShuffles all characters of text
{{ shuffle "Yes sir, Mister Johnson" }}
Result: nt Yor shJrseion Me,sis
snakecasetextSnake-cases text
{{ snakecase "BeginTheAwakening" }}
Result: begin_the_awakening
squotestr1, str2, ...Wrap all args with '
{{ squote "Ohoh! \" some characters ' here" }}
Result: 'Ohoh! " some characters ' here'
stripHTMLtextStrips HTML-specific chars from text and formats the result
{{ stripHTML "Hello!<br/>Wussup?" }}
Result:
Hello!
Wussup?
substrstart, end, textSubstring of text
{{ substr 4 10 "Yes sir, Mister Johnson" }}
Result: sir, M
swapcasetextSwaps upper-case with lower-case in text
{{ swapcase "Yes sir, Mister Johnson" }}
Result: yES SIR, mISTER jOHNSON
titletextTitle-cases text
{{ title "Yes sir, mister johnson" }}
Result: Yes Sir, Mister Johnson
trimtextRemoved any whitespace/newline from beginning and end of text
{{ trim " ohoh   " }}!
Result: ohoh!
trimAllset, textRemoves all occurrences of each set character from both ends of text
{{ trimAll "-_" "--Some text__" }}
Result: Some text
trimPrefixprefix, textRemoves prefix from beginning of text
{{ trimPrefix "--" "--Some text__" }}
Result: Some text__
trimSuffixsuffix, textRemoves suffix from ending of text
{{ trimSuffix "__" "--Some text__" }}
Result: --Some text
trunclength, textTruncates text at the provided length
{{ trunc 5 "Do not go gentle into that good night" }}
Result: Do no
untitletextUn-title-cases text
{{ untitle "Yes sir, MISTER Johnson" }}
Result: yes sir, mISTER johnson
uppertextUpper-cases text
{{ upper "Yes sir, Mister Johnson" }}
Result: YES SIR, MISTER JOHNSON
wraplength, textWrap text with newlines to desired length
{{ wrap 10 "Do not go gentle into that good night" }}
Result:
Do not go
gentle
into that
good night
wrapWithlength, sep, textWrap text with sep to desired length
{{ wrapWith 10 "#" "Do not go gentle into that good night" }}
Result: Do not go#gentle#into that#good night

String lists

Function nameArgsOutputExample
joinseparator, listJoins list items using separator
{{ join "-" (splitList "," "a,b,c,d") }}
Result: a-b-c-d
listFindRegexlist, regexReturns the first entry of list that matches the regular expression regex. It evaluates only string elements of list
{{$a := list "oh my lol" "hello world"}}{{listFindRegex $a "[wo]rl"}}
Result: hello world
sortAlphalistSorts list ascendingly
{{ sortAlpha (splitList "," "d,a,c,g,e,e6,e0") }}
Result: [a c d e e0 e6 g]
splitseparator, textSplits text into a map using separator
{{ dump (split "," "abc,def,ghi") }}
Result:
_0: abc
_1: def
_2: ghi
splitListseparator, textSplits text into a list using separator
{{ dump (splitList "," "abc,def,ghi") }}
Result:
- abc
- def
- ghi
splitnseparator, n, textSplits text into a map using separator, and limiting the split count by n
{{ dump (splitn "," 3 "abc,def,ghi,jkl,mno,pqr") }}
Result:
_0: abc
_1: def
_2: ghi,jkl,mno,pqr
toStringsvalueConverts value to a string list
{{ dump (toStrings (until 3)) }}
Result:
- "0"
- "1"
- "2"

URLs

Function nameArgsOutputExample
urlJoinmapJoins map (dictionary) into a URL string
{{ urlJoin (dict "host" "host:80" "path" "/path" "query" "query" "scheme" "http") }}
Result: http://host:80/path?query
urlParsetextParses text into a dictionary with URL parts
{{ dump (urlParse "http://admin:secret@server.com:8080/api?list=false#anchor") }}
Result:
fragment: anchor
host: server.com:8080
hostname: server.com
opaque: ""
path: /api
query: list=false
scheme: http
userinfo: admin:secret

Crypto

Function nameArgsOutputExample
adler32sumtextAdler-32 hash of text
{{ adler32sum "hello" }}
Result: 103547413
b32enctextBase64-encoded text
{{ b32enc "hello in 32!" }}
Result: NBSWY3DPEBUW4IBTGIQQ====
b64decb64Decodes b64 with Base64-encoding
{{ b32dec "JBGDIPY=" }}
Result: HL4?
b64decb64Decodes b64 with Base64-encoding
{{ b64dec "SEwzIQ==" }}
Result: HL3!
b64decUrlb64Decodes b64 with Base64-encoding (URL-friendly)
{{ b64decUrl "T2ghIFNwZWNpYWwgY2hhcnMg8J-YgQ=" }}
Result: Oh! Special chars 😁
b64enctextBase64-encoded text
{{ b64enc "Hello 🐄" }}
Result: SGVsbG8g8J+QhA==
b64encUrltextBase64-encoded text (URL-friendly)
{{ b64encUrl "Hello 🐄" }}
Result: SGVsbG8g8J-QhA==
htpasswdusername, passwordGenerates an htpasswd  compatible hash from username and password
{{ htpasswd "admin" "ohmylol" }}
Result: admin:$2a$10$7jlt72Apy7j9oLG88eSOOO7nTMJ.J7UoImeV9O0VNiuStZdPls4gS
sha1sumtextSHA1 hash of text
{{ sha1sum "hello" }}
Result: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
sha256sumtextSHA256 hash of text
{{ sha256sum "hello" | abbrev 40 }}
Result: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161...

Conversions

Function nameArgsOutputExample
atoitextConverts test to an integer
{{ add (atoi "25") 3 }}
Result: 28
float64valueConverts value to float64
{{ float64 "1.234" }}
Result: 1.234
int64valueConverts value to int64
{{ int64 "42" }}
Result: 42
intvalueConverts values to int
{{ int 45.34 }}
Result: 45
parseJsontextParses text using JSON, fails on error
{{ parseJson "{\"a\": 4}" }}
Result: map[a:4]
parseYamltextParses text using YAML, fails on error
{{ parseYaml "a: 5" }}
Result: map[a:5]
toDecimaltextConverts text from octal to decimal
{{ toDecimal "764" }}
Result: 500

Arithmetic (int)

Note: all the following functions convert all their parameters to int64 before performing any operation. This means any decimal numbers precision will be lost. For decimal/floating arithmetic, please use the Arithmetic (float) functions.

Function nameArgsOutputExample
add1numberAdds 1 to number
{{ add1 13 }}
Result: 14
addn1, n2, …Sum of all n*
{{ add 2 4 7.2 }}
Result: 13
biggest/maxn1, n2, …Returns the biggest of n*
{{ max 13 34 25 }}
Result: 34
divn1, n2n1 / n2
{{ div 25 4 }}
Result: 6
minn1, n2, …Returns the smallest of n*
{{ min 13 34 25 }}
Result: 13
modn1, n2Remainder of n1 / n2
{{ mod 25 4 }}
Result: 1
muln1, n2, …Multiplication of all n*
{{ mul 2 3 4 }}
Result: 24
subn1, n2n1 - n2
{{ sub 10 7 }}
Result: 3
untillimitint list, from 0 to limit (excluded)
{{ until 5 }}
Result: [0 1 2 3 4]
untilStepstart, end, stepint list, from start to end (excluded), with step
{{ untilStep 3 9 2 }}
Result: [3 5 7]

Arithmetic (float)

Function nameArgsOutputExample
addf1numberAdds 1 to number
{{ addf1 13 }}
Result: 14
addfn1, n2, …Sum of all n*
{{ addf 2 4 7.2 }}
Result: 13.2
biggestf/maxfn1, n2, …Returns the biggest of n*
{{ maxf 13 34 25 }}
Result: 34
ceilnLeast integer value greater than or equal to n
{{ ceil 7.2 }}
Result: 8
divfn1, n2n1 / n2
{{ divf 25 4 }}
Result: 6.25
floornGreatest integer value less than or equal to n
{{ floor 7.2 }}
Result: 7
minfn1, n2, …Returns the smallest of n*
{{ minf 13 34 25 }}
Result: 13
mulfn1, n2, …Multiplication of all n*
{{ mulf 2 3 4 }}
Result: 24
roundn, p, [rp]Rounds n to have p decimal places, using rp (default 0.5) as roundness threshold.
{{ round 7.256 2 }}, {{ round 7.34 1 0.4 }}
Result: 7.26, 7.4
subfn1, n2n1 - n2
{{ subf 10 7 }}
Result: 3

Utilities

Function nameArgsOutputExample
coalescev1, v2, …Returns the first non-empty v*
{{ coalesce "" "" "hi!" }}, {{ coalesce nil nil 4 }}
Result: hi!, 4
compactlistReturns a copy of list without any empty value
{{ compact (splitList "," "a,,c,,e,f") }}
Result: [a c e f]
deepCopyvalueCreates a deep-clone of value
{{$a := dict "a" 12 "b" 34}}{{$v := deepCopy $a}}{{$_ := unset $v "b"}}{{printf "%v -> %v" $a $v}}
Result: map[a:12 b:34] -> map[a:12]
defaultdef, valueReturns value, or def if value is empty (see empty function below)
{{ default "hello!" "" }}, {{ default 5 0 }}
Result: hello!, 5
emptyvalueTrue if value has the zero value for its type
{{ empty nil }}, {{ empty 0 }}
Result: true, true
ternaryvtrue, vfalse, testReturns vtrue if test is true, otherwise returns vfalse
{{ ternary "I'm true!" "So false!" (gt 1 0) }}
Result: I'm true!
toJson,toJSONvalueEncodes value into a JSON string
{{ toJson (split "," "a,b,c,<script>") }}
Result: {"_0":"a","_1":"b","_2":"c","_3":"\u003cscript\u003e"}
toPrettyJsonvalueEncodes value into a pretty (indented) JSON string
{{ toPrettyJson (split "," "a,b,c,<script>") }}
Result:
{
  "_0": "a",
  "_1": "b",
  "_2": "c",
  "_3": "\u003cscript\u003e"
}
toRawJsonvalueEncodes value into a JSON string with no escaping of HTML characters
{{ toRawJson (split "," "a,b,c,<script>") }}
Result: {"_0":"a","_1":"b","_2":"c","_3":"<script>"}
toYaml,toYAMLvalueEncodes value into a YAML string
{{ toYAML (dict "name" "Mr. Anderson" "list" (list 1 2 3)) }}
Result:
list:
- 1
- 2
- 3
name: Mr. Anderson

Reflection

If you define a struct named Foo, the kind is struct and the type is Foo. [source ]

Function nameArgsOutputExample
deepEqualx, yTrue if x and y are equal in value
{{ deepEqual (dict "a" "b") (dict "a" "b") }}
Result: true
kindIstarget, srcTrue if kind of src is target
{{ kindIs "mmm" 1.234 }}
Result: false
kindOfvalueGo-kind of value
{{ kindOf "hi!" }}, {{ kindOf 1.123 }}, {{ kindOf (dict "a" 34 ) }}, {{ kindOf (list 1 2) }}
Result: string, float64, map, slice
typeIstarget, srcTrue if type of src is target
{{ typeIs "float64" 1.234 }}
Result: true
typeOfvalueGo-type of value
{{ typeOf "hi!" }}, {{ typeOf 1.123 }}, {{ typeOf (dict "a" 34 ) }}, {{ typeOf (list 1 2) }}
Result: string, float64, map[string]interface {}, []interface {}

Lists, dictionaries

Function nameArgsOutputExample
append,pushlist, valueAppends value to list. Returns list
{{$l := until 5}}{{append $l "hello!"}}
Result: [0 1 2 3 4 hello!]
concatlist1, list2, …Returns a list made of all elements of all list* lists
{{ concat (until 5) (until 3) (until 2) }}
Result: [0 1 2 3 4 0 1 2 0 1]
dictk1, v1, k2, v2, …Dictionary made of all k*=v* pairs
{{ dict "a" 1 "b" 2 }}
Result: map[a:1 b:2]
firstlistFirst value of list
{{ first (until 5) }}
Result: 0
getmap, keyReturns key element of map
{{$a := dict "myKey" 4}}{{get $a "myKey"}}
Result: 4
hasitem, listTrue if list contains item
{{ has 2 (until 7) }}
Result: true
hasKeymap, keyTrue if map contains key
{{$a := dict "a" 4 "b" 5}}{{hasKey $a "b"}}
Result: true
initiallist“Head” of list (everything but last item)
{{ initial (until 5) }}
Result: [0 1 2 3]
keysmap1, map2, …Returns a list of all keys of all map* dictionaries
{{ keys (dict "a" 1) (dict "b" 4) }}
Result: [a b]
lastlistLast value of list
{{ last (until 5) }}
Result: 4
mergedst, srcCopies all src elements into dst, if dst corresponding elements are empty. Returns dst
{{$a := dict "a" 1 "b" 2}}{{merge $a (dict "a" 88 "c" 5)}}
Result: map[a:1 b:2 c:5]
mergeOverwritedst, srcCopies all src elements into dst, overwriting corresponding existing dst elements. Returns dst
{{$a := dict "a" 1 "b" 2}}{{mergeOverwrite $a (dict "a" 88 "c" 5)}}
Result: map[a:88 b:2 c:5]
mustMergedst, srcCopies all src elements into dst, if dst corresponding elements are empty. Returns dst, fails on error
{{$a := dict "a" 1 "b" 2}}{{mustMerge $a (dict "a" 88 "c" 5)}}
Result: map[a:1 b:2 c:5]
mustMergeOverwritedst, srcCopies all src elements into dst, overwriting corresponding existing dst elements. Returns dst, fails on error
{{$a := dict "a" 1 "b" 2}}{{mustMergeOverwrite $a (dict "a" 88 "c" 5)}}
Result: map[a:88 b:2 c:5]
omitmap, key1, key2, …Returns a clone of map without any key* key
{{ omit (split "," "a,b,c,d,e") "_0" "_3" "_10" }}
Result: map[_1:b _2:c _4:e]
pickmap, key1, key2, …Extract all key* keys of map into a new dictionary
{{ pick (split "," "a,b,c,d,e") "_0" "_3" "_10" }}
Result: map[_0:a _3:d]
pluckkey, map1, map2, …Returns a list containing all values of key in all map* dictionaries
{{ pluck "a" (dict "a" 1) (dict "a" 4) }}
Result: [1 4]
prependlist, valuePrepends value to list. Returns list
{{$l := until 5}}{{prepend $l "hello!"}}
Result: [hello! 0 1 2 3 4]
restlistTail of list (everything but first item)
{{ rest (until 5) }}
Result: [1 2 3 4]
reverselistReversed copy of list
{{ reverse (until 5) }}
Result: [4 3 2 1 0]
seqendGenerates all counting integers between 1 and end inclusive
{{ seq 5 }}, {{ seq -2 }}
Result: 1 2 3 4 5, 1 0 -1 -2
seqstart, endGenerates all counting integers between start and end inclusive incrementing or decrementing by 1
{{ seq 3 7 }}, {{ seq 3 -3 }}
Result: 3 4 5 6 7, 3 2 1 0 -1 -2 -3
seqstart, step, endGenerate all counting integers between start and end inclusive incrementing or decrementing by step
{{ seq 3 4 20 }}, {{ seq 1 -2 -5 }}
Result: 3 7 11 15 19, 1 -1 -3 -5
setmap, key, valueSets key=value in map. Returns map
{{$a := dict "myKey" 4}}{{set $a "key2" "Hello!"}}
Result: map[key2:Hello! myKey:4]
slicelist, start, [end]Returns a subset of list, starting from start index (inclusive) up to end index (exclusive)
{{ slice (splitList "," "a,b,c,d,e,f") 1 4 }}
Result: [b c d]
tuple,listv1, v2, …List made of all v* elements
{{ list 1 2 3 }}
Result: [1 2 3]
uniqlistUnique values of list
{{ uniq (splitList "," "a,b,c,a,a,d,b") }}
Result: [a b c d]
unsetmap, keyRemoves key from map. Returns `map |
{{$a := dict "a" 4 "b" 5}}{{unset $a "b"}}
Result: map[a:4]
|
valuesmap1, map2, …Returns a list of all values of all map* dictionaries
{{ values (dict "a" 1) (dict "b" 4) }}
Result: [1 4]
withoutlist, el1, el2, …Copy of list, without any el* element
{{ without (until 7) 3 4 }}
Result: [0 1 2 5 6]

Regular expressions

Function nameArgsOutputExample
mustRegexMatchregex, textTrue if regex matches text, fails on error
{{ regexMatch "[Hh]ello!" "hello!" }}
Result: true
regexFindregex, textReturns the first match of regex in text
{{ regexFind "se\\w+" "Unforseen consequences" }}
Result: seen
regexFindAllregex, text, nReturns all matches of regex in text, with max n matches
{{ regexFindAll "se\\w+" "Unforseen consequences see?" 2 }}
Result: [seen sequences]
regexMatchregex, textTrue if regex matches text, false on error
{{ regexMatch "[Hh]ello!" "hello!" }}
Result: true
regexReplaceAllregex, text, replReplaces all matches of regex in text with repl
{{ regexReplaceAll "se(\\w+)" "Unforseen consequences" "be$1" }}
Result: Unforbeen conbequences
regexReplaceAllLiteralregex, text, replReplaces all matches of regex in text with repl without using values expansion
{{ regexReplaceAllLiteral "se(\\w+)" "Unforseen consequences" "be$1" }}
Result: Unforbe$1 conbe$1
regexSplitregex, text, nSplits text using regex as delimiter, with max n substrings
{{ dump (regexSplit "a*" "abaabaccadaaae" 5) }}
Result:
- ""
- b
- b
- c
- cadaaae

Semantic version

Note: this chapter was originally written by Sprig library’s authors .

Some version schemes are easily parseable and comparable. Sprig provides functions for working with SemVer 2  versions.

semver

The semver function parses a string into a Semantic Version:

$version := semver "1.2.3-alpha.1+123"

If the parser fails, it will cause template execution to halt with an error.

At this point, $version is a pointer to a Version object with the following properties:

  • $version.Major: The major number (1 above)
  • $version.Minor: The minor number (2 above)
  • $version.Patch: The patch number (3 above)
  • $version.Prerelease: The prerelease (alpha.1 above)
  • $version.Metadata: The build metadata (123 above)
  • $version.Original: The original version as a string

Additionally, you can compare a Version to another version using the Compare function:

semver "1.4.3" | (semver "1.2.3").Compare

The above will return -1.

The return values are:

  • -1 if the given semver is greater than the semver whose Compare method was called
  • 1 if the version who’s Compare function was called is greater.
  • 0 if they are the same version

(Note that in SemVer, the Metadata field is not compared during version comparison operations.)

semverCompare

A more robust comparison function is provided as semverCompare. This version supports version ranges:

  • semverCompare "1.2.3" "1.2.3" checks for an exact match
  • semverCompare "^1.2.0" "1.2.3" checks that the major and minor versions match, and that the patch number of the second version is greater than or equal to the first parameter.

The SemVer functions use the Masterminds semver library , from the creators of Sprig.

Basic Comparisons

There are two elements to the comparisons. First, a comparison string is a list of space or comma separated AND comparisons. These are then separated by || (OR) comparisons. For example, ">= 1.2 < 3.0.0 || >= 4.2.3" is looking for a comparison that’s greater than or equal to 1.2 and less than 3.0.0 or is greater than or equal to 4.2.3.

The basic comparisons are:

  • =: equal (aliased to no operator)
  • !=: not equal
  • >: greater than
  • <: less than
  • >=: greater than or equal to
  • <=: less than or equal to

Note, according to the Semantic Version specification pre-releases may not be API compliant with their release counterpart. It says,

Working With Prerelease Versions

Pre-releases, for those not familiar with them, are used for software releases prior to stable or generally available releases. Examples of prereleases include development, alpha, beta, and release candidate releases. A prerelease may be a version such as 1.2.3-beta.1 while the stable release would be 1.2.3. In the order of precedence, prereleases come before their associated releases. In this example 1.2.3-beta.1 < 1.2.3.

According to the Semantic Version specification prereleases may not be API compliant with their release counterpart. It says,

A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.

SemVer comparisons using constraints without a prerelease comparator will skip prerelease versions. For example, >=1.2.3 will skip prereleases when looking at a list of releases while >=1.2.3-0 will evaluate and find prereleases.

The reason for the 0 as a pre-release version in the example comparison is because pre-releases can only contain ASCII alphanumerics and hyphens (along with . separators), per the spec. Sorting happens in ASCII sort order, again per the spec. The lowest character is a 0 in ASCII sort order (see an ASCII Table )

Understanding ASCII sort ordering is important because A-Z comes before a-z. That means >=1.2.3-BETA will return 1.2.3-alpha. What you might expect from case sensitivity doesn’t apply here. This is due to ASCII sort ordering which is what the spec specifies.

Hyphen Range Comparisons

There are multiple methods to handle ranges and the first is hyphens ranges. These look like:

  • 1.2 - 1.4.5 which is equivalent to >= 1.2 <= 1.4.5
  • 2.3.4 - 4.5 which is equivalent to >= 2.3.4 <= 4.5

Wildcards In Comparisons

The x, X, and * characters can be used as a wildcard character. This works for all comparison operators. When used on the = operator it falls back to the patch level comparison (see tilde below). For example,

  • 1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • >= 1.2.x is equivalent to >= 1.2.0
  • <= 2.x is equivalent to < 3
  • * is equivalent to >= 0.0.0

Tilde Range Comparisons (Patch)

The tilde (~) comparison operator is for patch level ranges when a minor version is specified and major level changes when the minor number is missing. For example,

  • ~1.2.3 is equivalent to >= 1.2.3, < 1.3.0
  • ~1 is equivalent to >= 1, < 2
  • ~2.3 is equivalent to >= 2.3, < 2.4
  • ~1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • ~1.x is equivalent to >= 1, < 2

Caret Range Comparisons (Major)

The caret (^) comparison operator is for major level changes once a stable (1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts as the API stability level. This is useful when comparisons of API versions as a major change is API breaking. For example,

  • ^1.2.3 is equivalent to >= 1.2.3, < 2.0.0
  • ^1.2.x is equivalent to >= 1.2.0, < 2.0.0
  • ^2.3 is equivalent to >= 2.3, < 3
  • ^2.x is equivalent to >= 2.0.0, < 3
  • ^0.2.3 is equivalent to >=0.2.3 <0.3.0
  • ^0.2 is equivalent to >=0.2.0 <0.3.0
  • ^0.0.3 is equivalent to >=0.0.3 <0.0.4
  • ^0.0 is equivalent to >=0.0.0 <0.1.0
  • ^0 is equivalent to >=0.0.0 <1.0.0

Sprig - unavailable functions

If you use the Sprig  library in other projects, you may want to know that the following functions have been disabled for security/performance/non-usefulness reasons:

  • fail: if you want a template to not render, please use a trigger condition
  • env
  • expandenv
  • getHostByName
  • base
  • dir
  • clean
  • ext
  • isAbs
  • genPrivateKey
  • derivePassword
  • buildCustomCert
  • genCA
  • genSelfSignedCert
  • genSignedCert
  • encryptAES
  • decryptAES

Legacy functions

These functions are available for reference, for historical reasons:

ParseJSON

Parses a JSON string to a map.

Template Payload
{{ $content := .value | ParseJSON }}
Hello {{ $content.name }}!
{
  "value": "{\"name\": \"Mr. Anderson\"}"
}
Rendered
Hello Mr. Anderson!

ParseYAML

Parses a YAML string to a map.

Template Payload
{{ $content := .value | ParseYAML }}
Hello {{ $content.name }}!
{
  "value": "name: Mr. Anderson"
}
Rendered
Hello Mr. Anderson!

GetTimeNow

Returns the current time (UTC) as a time.Time  element, which can be formatted as desired, following Go language time formatting  convention (more examples ).

Template
{{ $time := GetTimeNow -}}

ISO 8601: {{ $time.Format "2006-01-02T15:04:05" }} / yyyy-MM-dd'T'HH:mm:ss
ISO 8601: {{ $time.Format "2006-01-02T15:04:05-0700" }} / yyyy-MM-dd'T'HH:mm:ssZ	
{{ $time.Format "2 Jan 2006 15:04:05" }} / d MMM yyyy HH:mm:ss				
RFC 822: {{ $time.Format "Mon, 2 Jan 2006 15:04:05 MST" }} / EEE, d MMM yyyy HH:mm:ss z
Rendered
ISO 8601: 2020-09-24T06:58:07 / yyyy-MM-dd'T'HH:mm:ss
ISO 8601: 2020-09-24T06:58:07+0000 / yyyy-MM-dd'T'HH:mm:ssZ	
24 Sep 2020 06:58:07 / d MMM yyyy HH:mm:ss				
RFC 822: Thu, 24 Sep 2020 06:58:07 UTC / EEE, d MMM yyyy HH:mm:ss z

Parse unix time

Parses the input value to a time.Time  element.

Template Payload
Result: {{ .result }}!
 
{{ $parsedTimeMs := .timeMs | ParseUnixTimeMs -}}
Time (milliseconds): {{ $parsedTimeMs.String }}

{{ $parsedTimeSeconds := .time | ParseUnixTime -}}
Time (seconds): {{ $parsedTimeSeconds.String }}

We can parse also a string: {{ .timeStr | ParseUnixTime }}
{
  "result": "success",
  
  "timeMs": 1549049482225,
  "time": 1549049482,
  
  "timeStr": "1549049482"
}
Rendered
Result: success!
 
Time (milliseconds): 2019-02-01 19:31:22.225 +0000 UTC

Time (seconds): 2019-02-01 19:31:22 +0000 UTC

We can parse also a string: 2019-02-01 19:31:22 +0000 UTC

Base64 encode/decode

Template
The message says "{{ .valueBase64Std | Base64Decode }}".

I'd like to answer back with "{{ "Hello to you too!" | Base64Encode }}"! 
    
What do we have here? {{ .valueBase64URL | Base64DecodeURL }}
Rendered
The message says "Hello 🐄".

I'd like to answer back with "SGVsbG8gdG8geW91IHRvbyE="! 
    
What do we have here? Oh! Special chars 😁
Payload
{
  "valueBase64Std": "SGVsbG8g8J+QhA=",
  "valueBase64URL": "T2ghIFNwZWNpYWwgY2hhcnMg8J-YgQ="
}

Notify17 also supports encoding/decoding URL-safe base64  with Base64EncodeURL and Base64DecodeURL.