Skip to content

Useful Jinja Filters and Extension in APIO

Key Filters

  • tojson: Converts a dictionary to a JSON Object.
jinja
{{ data | tojson }}
  • json: Converts a JSON string into a dictionary for further manipulation.
jinja
{{ context.response | json }}
  • pp_dict: Formats a dictionary into a pretty-printed JSON Object.
jinja
{{ data | pp_dict }}
  • combine: Merges dictionaries.
jinja
{{ request.body | combine(context.response | json) }}
  • dict_filter: Filters dictionary entries by key.
jinja
{{ request.body | dict_filter("firstName") }}

Constructing Dynamic JSON Structure

Example: Including only non-empty values

Let's start with a simple example, we have the dictionary context provided in the APIO environment.

json
{
  "context":{
    "eid": {"value": "12345"},
    "iccid": "",
    "profileType": "test"
  }
}

Let's say that we want to construct a JSON Object inside an APIO workflow including only the keys in the dictionary context containing non-empty values. We can use the following solution where we benefit from Jinja's ability to conditionally include attributes and handle commas dynamically.

jinja
{% set data = {} -%}
{% if context.eid -%}
  {% set _ = data.update({"eid": context.eid}) -%}
{% endif -%}
{% if context.iccid -%}
  {% set _ = data.update({"iccid": context.iccid}) -%}
{% endif -%}
{% if context.profileType -%}
  {% set _ = data.update({"profileType": context.profileType}) -%}
{% endif -%}
{{ data | tojson }}

Where data is an empty dictionary initialized to store key-value pairs dynamically based on some conditions. The if statements check whether specific keys in context contain non-empty values. If a value exists, it is added to the data dictionary using update(). The expression if context.eid checks whether context.eid holds a truthy value. If this is the case, the dictionary is updated with a key "eid" and its corresponding value from context.eid. The expression {{data | tojson}} converts the data dictionary into a JSON Object for output.

Exercise

Copy/paste the data from this subsection to the template playground, check the result. Change the context data, and check the result.

Best Practices

Use the Right Notation:

  • Use dot notation for valid Python identifiers.
  • Use bracket notation for keys with special characters.

Error Handling:

  • Ensure JSON strings are valid before parsing.
  • Use the | json filter cautiously and validate inputs.

Compact JSON:

  • Use | tojson to generate compact JSON Objects for output.

A note on handling throwable variables

In the code, _ is a common convention used in Jinja (and Python) to denote a throwaway variable. It's used when the result of an operation is not needed directly but the operation itself needs to be performed. In the following example,

jinja
{% set data = {} -%}
{% if context.eid -%}
    {% set _ = data.update({"eid": context.eid}) -%}
{% endif -%}
{% if context.iccid -%}
    {% set _ = data.update({"iccid": context.iccid}) -%}
{% endif -%}
{% if context.profileType -%}
    {% set _ = data.update({"profileType": context.profileType}) -%}
{% endif -%}
{{ data | tojson }}

the update() method updates the dictionary data in place with the specified key-value pair (e.g., {"eid": context.eid}). However, update() returns None (it doesn't return the updated dictionary). Assigning the result of update() (which is None) to _ serves to perform the update operation without needing the return value. The _ variable is used as a "placeholder" to indicate that the result is intentionally ignored. By convention, we use _ to signal to others reading the code that the variable is not used elsewhere. It is nevertheless required by Jinja: Jinja's {% set %} requires a variable to assign the result of an operation. Since the operation itself (update) is important but the result is not, _ is used.