- Working with Templates
- Kong Template Helpers - Lua API
- l(key, fallback)
- each(list_or_table)
- print(any)
- markdown(string)
- json_encode(object)
- json_decode(string)
portal
- page
- user
- theme
- str
- Usage
- Methods
- str. byte
- str. char
- str. dump
- str. find
- str. format
- str. gfind
- str. gmatch
- str. gsub
- str. len
- str. lower
- str. match
- str. rep
- str. reverse
- str. sub
- str. upper
- str. isalpha
- str. isdigit
- str. isalnum
- str. isspace
- str. islower
- str. isupper
- str. startswith
- str. endswith
- str. join
- str. splitlines
- str. split
- str. expandtabs
- str. lfind
- str. rfind
- str. replace
- str. count
- str. ljust
- str. rjust
- str. center
- str. lstrip
- str. rstrip
- str. strip
- str. splitv
- str. partition
- str. rpartition
- str. at
- str. lines
- str. title
- str. shorten
- str. quote_string
- tbl
- Usage
- Methods
- tbl. getn
- tbl. setn
- tbl. maxn
- tbl. insert
- tbl. remove
- tbl. concat
- tbl. map
- tbl. foreach
- tbl. foreachi
- tbl. sort
- tbl. sortv
- tbl. filter
- tbl. size
- tbl. index_by
- tbl. transform
- tbl. range
- tbl. reduce
- tbl. index_map
- tbl. makeset
- tbl. union
- tbl. intersection
- tbl. count_map
- tbl. set
- tbl. new
- tbl. clear
- tbl. removevalues
- tbl. readonly
- tbl. update
- tbl. copy
- tbl. deepcopy
- tbl. icopy
- tbl. move
- tbl. insertvalues
- tbl. deepcompare
- tbl. compare
- tbl. compare_no_order
- tbl. find
- tbl. find_if
- tbl. search
- tbl. keys
- tbl. values
- tbl. sub
- tbl. merge
- tbl. difference
- tbl. zip
Working with Templates
Kong Portal is built on top of the lua-resty-template
templating library, which can be viewed here: https://github.com/bungle/lua-resty-template. Basic usage of the library will be described below. Refer to the source documentation for a more in-depth look at what it can accomplish.
Syntax
(excerpt from lua-resty-templates documentation)
You may use the following tags in templates:
{{expression}}
, writes result of expression - html escaped{*expression*}
, writes result of expression{% lua code %}
, executes Lua code{(path-to-partial)}
, includepartial
file by path, you may also supply context for the file{(partials/header.html, { message = "Hello, World" } )}
{-block-}...{-block-}
, wraps inside of a{-block-}
to a value stored in ablocks
table with a keyblock
(in this case), see using blocks. Don’t use predefined block namesverbatim
andraw
.{-verbatim-}...{-verbatim-}
and{-raw-}...{-raw-}
are predefined blocks whose inside is not processed by thelua-resty-template
but the content is outputted as is.{# comments #}
everything between{#
and#}
is considered to be commented out (i.e., not outputted or executed).
Show custom properties
You may work with custom properties in your OpenAPI spec. To expose custom properties in Dev Portal, change the property showExtensions
to true
in the spec-renderer.html
file. By default, showExtensions
is false
.
Partials
Partials are snippets of html that layouts can reference. Partials have access to all the same data that its layout does, and can even call other partials. Breaking your code into partials can help organize large pages, as well as allow different layouts share common page elements.
content/index.txt
---
layout: index.html
title: Partials
header_logo: assets/images/example.jpeg
header_nav_items:
about:
href: /about
guides:
href: /guides
hero_title: Partials Info
hero_description: Partials are wicked sick!
---
layouts/index.html
{(partials/header.html)}
<div class="content">
{(partials/hero.html)}
</div>
{(partials/footer.html)}
partials/header.html
<header class="row">
<div class="column">
<img src="{{page.header_logo}}"/>
</div>
<div class="column">
{(partials/header_nav.html)}
</div>
</header>
partials/header_nav.html
<ul>
{% for title, href in each(page.header_nav_items) do %}
<li><a href="{{href}}">{{title}}</a></li>
{% end %}
</ul>
partials/hero.html
<h1>{{page.hero_title}}</h1>
<p>{{page.hero_description}}</p>
partials/hero.html
<footer>
<p>footer</p>
</footer>
Output:
<header class="row">
<div class="column">
<img src="assets/images/example.jpeg"/>
</div>
<div class="column">
<ul>
<li><a href="/about">about</a></li>
<li><a href="/guieds">guides</a></li>
</ul>
</div>
</header>
<h1>Partials Info</h1>
<p>Partials are wicked sick!</p>
<footer>
<p>footer</p>
</footer>
Blocks
Blocks can be used to embed a view or partial into another template. Blocks are particularly useful when you want different templates to share a common wrapper.
In the example below, notice that the content file is referencing index.html
, and not wrapper.html
.
content/index.txt
---
layout: index.html
title: Blocks
description: Blocks are the future!
---
layouts/index.html
{% layout = "layouts/wrapper.html" %} <- syntax declaring where to find the block
{-main-} <- delimiter describing what content renders in block
<div class="content">
<h1>{{page.title}}</h1>
<p>{{page.description}}<p>
</div>
{-main-}
layouts/wrapper.html
<!DOCTYPE html>
<html>
<head>
<title>Testing lua-resty-template blocks</title>
</head>
<body>
<header>
<p>header</p>
</header>
{*main*} <- syntax indicating where to place the block
<footer>
<p>footer</p>
</footer>
</body>
</html>
Output:
<!DOCTYPE html>
<html>
<head>
<title>Testing lua-resty-template blocks</title>
</head>
<body>
<header>
<p>header</p>
</header>
<div class="content">
<h1>Blocks</h1>
<p>Blocks are the future!<p>
</div>
<footer>
<p>footer</p>
</footer>
</body>
</html>
Collections
Collections are a powerful tool enabling you to render sets of content as a group. Content rendered as a collection share a configurable route pattern, as well as a layout. Collections are configured in your portals portal.conf.yaml
file.
The example below shows all the necessary configuration/files needed to render a basic blog
collection made up of individual posts
.
portal.conf.yaml
name: Kong Portal
theme:
name: base
collections:
posts:
output: true
route: /:stub/:collection/:name
layout: post.html
Above you can see a collections
object was declared, which is made up of individual collection configurations. In this example, you are configuring a collection called posts
. The renderer looks for a root directory called _posts
within the content
folder for individual pages to render. If you created another collection conf called animals
, the renderer would look for a directory called _animals
for content files to render.
Each configuration item is made up of a few parts:
output
- required: false
- type:
boolean
- description: This optional attribute determines whether the collections should render or not. When set to
false
, virtual routes for the collection are not created.
route
- required: true
- type:
string
- default:
none
- description: The
route
attribute is required and tells the renderer what pattern to generate collection routes from. A collection route should always include at least one valid dynamic namespace that uniquely identifies each collection member.- Any namespace in the route declaration which begins with
:
is considered dynamic. - Only certain dynamic namespaces are recognized by Kong as valid:
:title
: Replaces namespace with a contentstitle
, declared in headmatter.:name
: Replaces namespace with the filename of a piece of content.:collection
: Replaces namespace with name of current collection.:stub
: Replaces namespace with value ofheadmatter.stub
in each contents headmatter.
- Any namespace in the route declaration which begins with
layout
- required: true
- type:
boolean
- description: The
layout
attribute determines what HTML layout the collections use to render. The path root is accessed from within the current themeslayouts
directory.
- type:
- required: true
content/_posts/post1.md
---
title: Post One
stub: blog
---
This is my first post!
content/_posts/post2.md
---
title: Post Two
stub: blog
---
This is my second post!
themes/base/layouts/post.html
<h1>{{ page.title }}</h1>
<p>{* page.body *}</p>
Output:
From <kong_portal_gui_url>/blog/posts/post1
:
<h1>Post One</h1>
<p>This is my first post!</p>
From <kong_portal_gui_url>/blog/posts/post2
:
<h1>Post Two</h1>
<p>This is my second post!</p>
Kong Template Helpers - Lua API
Kong Template Helpers are a collection of objects that give access to your portal data at the time of render and provide powerful integrations into Kong.
Globals:
- l - Locale helper, first version, gets values from the currently active page.
- each - Commonly used helper to iterate over lists or tables.
- print - Commonly used helper to print lists / tables.
- markdown - Commonly used helper to print lists / tables.
- json_decode - Decode JSON to Lua table.
- json_encode - Encode Lua table to JSON.
Objects:
- portal - The portal object refers to the current workspace portal being accessed.
- page - The page object refers to the currently active page and its contents.
- user - The user object represents the currently logged in developer accessing the Kong Portal.
- theme - The theme object represents the currently active theme and its variables.
- tbl = Table helper methods. Examples:
map
,filter
,find
,sort
. - str = String helper methods. Examples:
lower
,upper
,reverse
,endswith
. - helpers - Helper functions simplify common tasks or provide easy shortcuts to Kong Portal methods.
Terminology / Definitions:
list
- Also referred to commonly as an array ([1, 2, 3]
) in Lua is a table-like object ({1, 2, 3}
). Lua list index starts at1
not0
. Values can be accessed by array notation (list[1]
).table
- Also commonly known as an object or hashmap ({1: 2}
) in Lua looks like ({1 = 2}
). Values can be accessed by array or dot notation (table.one or table["one"]
).
l(key, fallback)
Returns the current translation by key from the currently active page.
Return Type
string
Usage
Using content/en/example.txt
:
---
layout: example.html
locale:
title: Welcome to {{portal.name}}
slogan: The best developer portal ever created.
---
Using content/es/example.txt
:
---
layout: example.html
locale:
title: Bienvenido a {{portal.name}}
slogan: El mejor portal para desarrolladores jamás creado.
---
Using layouts/example.html
:
<h1>{* l("title", "Welcome to" .. portal.name) *}</h1>
<p>{* l("slogan", "My amazing developer portal!") *}</p>
<p>{* l("powered_by", "Powered by Kong.") *}</p>
Output:
For en/example
:
<h1>Welcome to Kong Portal</h1>
<p>The best developer portal ever created.</p>
<p>Powered by Kong.</p>
For es/example
:
<h1>Bienvenido a Kong Portal</h1>
<p>El mejor portal para desarrolladores jamás creado.</p>
<p>Powered by Kong.</p>
Notes
l(...)
is a helper from thepage
object. It can be also accessed viapage.l
. However,page.l
does not support template interpolation (for example, `` will not work.)
each(list_or_table)
Returns the appropriate iterator depending on what type of argument is passed.
Return Type
Iterator
Usage
Template (List):
{% for index, value in each(table) do %}
<ul>
<li>Index: {{index}}</li>
<li>Value: {{ print(value) }}</li>
</ul>
{% end %}
Template (Table):
{% for key, value in each(table) do %}
<ul>
<li>Key: {{key}}</li>
<li>Value: {{ print(value) }}</li>
</ul>
{% end %}
print(any)
Returns stringified output of input value.
Return Type
string
Usage
Template (Table):
<pre>{{print(page)}}</pre>
markdown(string)
Returns HTML from the markdown string passed as an argument. If a string argument is not valid markdown, the function will return the string as is. To render properly, the helper should be used with raw {* *}
delimiters.
Return Type
string
Usage
Template (string as arg):
<pre>{* markdown("##This is Markdown") *}</pre>
Template (content val as arg):
<pre>{* markdown(page.description) *}</pre>
json_encode(object)
JSON encodes Lua table passed as argument
Return Type
string
Usage
Template:
<pre>{{ json_encode({ dog = cat }) }}</pre>
json_decode(string)
Decodes JSON string argument to Lua table
Return Type
table
Usage
Template:
<pre>{{ print(json_encode('{"dog": "cat"}')) }}</pre>
portal
portal
gives access to data relating to the current portal, this includes things like portal configuration, content, specs, and layouts.
- portal.workspace
- portal.url
- portal.api_url
- portal.auth
- portal.specs
- portal.specs_by_tag
- portal.developer_meta_fields
You can access the current workspace’s portal config directly on the portal
object like so:
portal[config_key] or portal.config_key
For example portal.auth
is a portal config value. You can find a list of config values by reading the portal section of kong.conf
.
From kong.conf
The portal only exposes config values that start with portal_
, and they can be access by removing the portal_
prefix.
Some configuration values are modified or customized, these customizations are documented under the Portal Members section.
portal.workspace
Returns the current portal’s workspace.
Return Type
string
Usage
Template:
{{portal.workspace}}
Output:
default
portal.url
Returns the current portal’s url with workspace.
Return Type
string
Usage
Template:
{{portal.url}}
Output:
http://127.0.0.1:8003/default
portal.api_url
Returns the configuration value for portal_api_url
with the current workspace appended.
Return Type
string or nil
Usage
Template:
{{portal.api_url}}
Output when portal_api_url = http://127.0.0.1:8004
:
http://127.0.0.1:8004/default
portal.auth
Returns the current portal’s authentication type.
Return Type
string
Usage
Printing a value
Input:
{{portal.auth}}
Output when portal_auth = basic-auth
:
basic-auth
Checking if authentication is enabled
Input:
{% if portal.auth then %}
Authentication is enabled!
{% end %}
Output when portal_auth = basic-auth
:
Authentication is endabled!
portal.specs
Returns an array of specification files contained within the current portal.
Return type
array
Usage
Viewing a content value
Template:
<pre>{{ print(portal.specs) }}</pre>
Output:
{
{
"path" = "content/example1_spec.json",
"content" = "..."
},
{
"path" = "content/documentation/example1_spec.json",
"content" = "..."
},
...
}
Looping through values
Template:
{% for _, spec in each(portal.specs) %}
<li>{{spec.path}}</li>
{% end %}
Output:
<li>content/example1_spec.json</li>
<li>content/documentation/example1_spec.json</li>
Filter by path
Template:
{% for _, spec in each(helpers.filter_by_path(portal.specs, "content/documentation")) %}
<li>{{spec.path}}</li>
{% end %}
Output:
<li>content/documentation/example1_spec.json</li>
portal.developer_meta_fields
Returns an array of developer meta fields available/required by Kong to register a developer.
Return Type
array
Usage
Printing a value
Template:
{{ print(portal.developer_meta_fields) }}
Output:
{
{
label = "Full Name",
name = "full_name",
type = "text",
required = true,
},
...
}
Looping through values
Template:
{% for i, field in each(portal.developer_meta_fields) do %}
<ul>
<li>Label: {{field.label}}</li>
<li>Name: {{field.name}}</li>
<li>Type: {{field.type}}</li>
<li>Required: {{field.required}}</li>
</ul>
{% end %}
Output:
<ul>
<li>Label: Full Name</li>
<li>Name: full_name</li>
<li>Type: text</li>
<li>Required: true</li>
</ul>
...
page
page
gives access to data relating to the current page, which includes things like page url, path, breadcrumbs, and more.
When you create a new content page, you are able to define key-values. Here you are going to learn how to access those values and a few other interesting things.
You can access the key-values you define directly on the page
object like so:
page[key_name] or page.key_name
You can also access nested keys like so:
page.key_name.nested_key
Be careful! To avoid output errors, make sure that the key_name
exists before accessing nested_key
as shown below:
{{page.key_name and page.key_name.nested_key}}
page.route
Returns the current page’s route/path.
Return Type
string
Usage
Template:
{{page.route}}
Output, given url is http://127.0.0.1:8003/default/guides/getting-started
:
guides/getting-started
page.url
Returns the current page’s url.
Return Type
string
Usage
Template:
{{page.url}}
Output, given url is http://127.0.0.1:8003/default/guides/getting-started
:
http://127.0.0.1:8003/default/guides/getting-started
page.breadcrumbs
Returns the current page’s breadcrumb collection.
Return Type
table[]
Item Properties
item.path
- Full path to item, no forward-slash prefix.item.display_name
- Formatted name.item.is_first
- Is this the first item in the list?item.is_last
- Is this the last item in the list?
Usage
Template:
<div id="breadcrumbs">
<a href="">Home</a>
{% for i, crumb in each(page.breadcrumbs) do %}
{% if crumb.is_last then %}
/ {{ crumb.display_name }}
{% else %}
/ <a href="{{crumb.path}}">{{ crumb.display_name }}</a>
{% end %}
{% end %}
</div>
page.body
Returns the body of the current page as a string. If the route’s content file has a .md
or .markdown
extension, the body will be parsed from markdown to html.
Return Type
string
Usage for .txt, .json, .yaml, .yml templates
index.txt
:
This is text content.
Template:
<h1>This is a title</h1>
<p>{{ page.body) }}</p>
Output:
> # This is a title
> This is text content.
Usage for .md, .markdown templates
Template (markdown): Use the raw delimiter syntax {* *}
to render markdown within a template.
index.txt
# This is a title
This is text content.
Template:
{* page.body *}
Output:
> # This is a title
> This is text content.
user
user
gives access to data relating to the currently authenticated user. User object is only applicable when KONG_PORTAL_AUTH
is enabled.
user.is_authenticated
Returns boolean
value as to the current user’s authentication status.
Return Type
boolean
Usage
Template:
{{print(user.is_authenticated)}}
Output:
true
user.has_role
Returns true
if a user has a role given as an argument.
Return Type
boolean
Usage
Template:
{{print(user.has_role("blue"))}}
Output:
true
user.get
Takes developer attribute as an argument and returns value if present.
Return Type
any
Usage
Template:
{{user.get("email")}}
{{print(user.get("meta"))}}
Output:
example123@konghq.com
{ "full_name" = "example" }
theme
The theme
object exposes values set in your theme.conf.yaml
file. In addition, any variable overrides contained in portal.conf.yaml
will be included as well.
theme.colors
Returns a table of color variables and their values as key-value pairs.
Return Type
table
Usage
theme.conf.yaml
:
name: Kong
colors:
primary:
value: '#FFFFFF'
description: 'Primary Color'
secondary:
value: '#000000'
description: 'Secondary Color'
tertiary:
value: '#1DBAC2'
description: 'Tertiary Color'
Template:
{% for k,v in each(theme.colors) do %}
<p>{{k}}: {{v}}</p>
{% end %}
Output:
<p>primary: #FFFFFF</p>
<p>secondary: #000000</p>
<p>tertiary: #1DBAC2</p>
theme.color
Description
Takes color var by string argument, returns value.
Return Type
string
Usage
theme.conf.yaml
:
name: Kong
colors:
primary:
value: '#FFFFFF'
description: 'Primary Color'
secondary:
value: '#000000'
description: 'Secondary Color'
tertiary:
value: '#1DBAC2'
description: 'Tertiary Color'
Template:
<p>primary: {{theme.color("primary")}}</p>
<p>secondary: {{theme.color("secondary")}}</p>
<p>tertiary: {{theme.color("tertiary")}}</p>
Output:
<p>primary: #FFFFFF</p>
<p>secondary: #000000</p>
<p>tertiary: #1DBAC2</p>
theme.fonts
Returns table of font vars and their values as key-value pairs.
Return Type
table
Usage
theme.conf.yaml
:
name: Kong
fonts:
base: Roboto
code: Roboto Mono
headings: Lato
Template:
{% for k,v in each(theme.fonts) do %}
<p>{{k}}: {{v}}</p>
{% end %}
Output:
<p>base: Roboto</p>
<p>code: Roboto Mono</p>
<p>headings: Lato</p>
theme.font
Takes font name by string argument, returns value.
Return Type
string
Usage
theme.conf.yaml
:
name: Kong
fonts:
base: Roboto
code: Roboto Mono
headings: Lato
Template:
<p>base: {{theme.font("base")}}</p>
<p>code: {{theme.font("code")}}</p>
<p>headings: {{theme.font("headings")}}</p>
Output:
<p>base: #FFFFFF</p>
<p>code: #000000</p>
<p>headings: #1DBAC2</p>
str
Table containing useful string helper methods.
Usage
.upper()
example:
<pre>{{ str.upper("dog") }}</pre>
Methods
str.byte
str.char
str.dump
str.find
str.format
str.gfind
str.gmatch
str.gsub
str.len
str.lower
str.match
str.rep
str.reverse
str.sub
str.upper
str.isalpha
str.isdigit
str.isalnum
str.isspace
str.islower
str.isupper
str.startswith
str.endswith
str.join
str.splitlines
str.split
str.expandtabs
str.lfind
str.rfind
str.replace
str.count
str.ljust
str.rjust
str.center
str.lstrip
str.rstrip
str.strip
str.splitv
str.partition
str.rpartition
str.at
str.lines
str.title
str.shorten
str.quote_string
tbl
Table containing useful table helper methods
Usage
.map()
example:
{% tbl.map({"dog", "cat"}, function(item) %}
{% if item ~= "dog" then %}
{% return true %}
{% end %}
{% end) %}