Using JMESPath in APIO workflows
JMESPath is a powerful query language for extracting and transforming JSON data. In APIO, the json_query
filter allows you to apply JMESPath expressions to JSON objects, enabling efficient data extraction and manipulation.
Basic Syntax and Notes
- Applying JMESPath: Use
| json_query(expression)
to apply a JMESPath expression to a JSON object. - Output Format: To convert the result into a JSON string, use the
| tojson
filter after the query. - Powerful Queries: JMESPath supports nested queries, slicing, projections, filters, and functions.
Examples of JMESPath Queries
All these examples can be tested with the template playground
Accessing a Simple Key
Input
{"test": {"a": "foo", "b": "bar", "c": "baz"}}
Query
{{ test | json_query("a") }}
Result
foo
Accessing Nested Keys
Input
{"test": {"a": {"b": {"c": {"d": "value"}}}}}
Query
{{ test | json_query("a.b.c.d") }}
Result
value
Accessing Elements in a List
Input
{"test": ["a", "b", "c", "d", "e", "f"]}
Query
{{ test | json_query("[1]") }}
Result
b
Accessing Deeply Nested Lists
Input
{
"test": {
"a": {
"b": {
"c": [
{
"d": [
0,
[1, 2]
]
},
{
"d": [
3,
4
]
}
]
}
}
}
}
Query
{{ test | json_query("a.b.c[0].d[1][0]") }}
Result
1
List Slicing
JMESPath supports Python-style slicing for lists. Input
{"test": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
Queries and results
- First 5 elements
{{ test | json_query("[0:5]") }}
Result: [0, 1, 2, 3, 4]
- Last 5 elements
{{ test | json_query("[5:10]") }}
Result: [5, 6, 7, 8, 9]
- Even indices
{{ test | json_query("[::2]") }}
Result: [0, 2, 4, 6, 8]
- Reverse order
{{ test | json_query("[::-1]") }}
Result: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
List and Sliced Projections
Input
{
"test": {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
]
}
}
Queries and results
- Extract first names
{{ test | json_query("people[*].first") }}
Result: ['James', 'Jacob', 'Jayden']
- Extract first names of the first two people:
{{ test | json_query("people[:2].first") }}
Result: ['James', 'Jacob']
- Project into a custom structure:
{{ test | json_query("people[*].{firstName: first}") }}
Result: [{"firstName":"James"},{"firstName":"Jacob"},{"firstName":"Jayden"},{"firstName":null}]
Object projections
Input
{"test": {
"ops": {
"functionA": {"numArgs": 2},
"functionB": {"numArgs": 3},
"functionC": {"variadic": true}
}
}}
Query
{{ test | json_query("ops.*.numArgs") }}
Result
[2, 3]
Flattening Nested Lists
Input
{
"test": {
"reservations": [
{
"instances": [
{"state": "running"},
{"state": "stopped"}
]
},
{
"instances": [
{"state": "terminated"},
{"state": "running"}
]
}
]
}
}
Queries and results:
- Extract grouped states
{{ test | json_query("reservations[].instances[*].state") }}
Result: [['running', 'stopped'], ['terminated', 'running']]
- Flatened states
{{ test | json_query("reservations[].instances[].state") }}
Result: ['running', 'stopped', 'terminated', 'running']
Filtering Lists
Input
{
"test": {
"machines": [
{"name": "a", "state": "running"},
{"name": "b", "state": "stopped"},
{"name": "b", "state": "running"}
]
}
}
Query
{{ test | json_query("machines[?state=='running'].name") }}
Result
['a', 'b']
Pie Expressions
MESPath supports chaining queries with pipes (|). Input
{
"test": {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
]
}
}
Query
{{ test | json_query("people[*].first | [0]") }}
Result
James
Multiselect Expressions
Input
{
"test": {
"people": [
{"name": "a", "state": {"name": "up"}},
{"name": "b", "state": {"name": "down"}},
{"name": "c", "state": {"name": "up"}}
]
}
}
Queries and results:
- Multiselect as a list of lists:
{{ test | json_query("people[].[name, state.name]") }}
Result: [['a', 'up'], ['b', 'down'], ['c', 'up']]
- Multiselect into objects:
{{ test | json_query("people[].{Name: name, State: state.name}") }}
Result: [{'Name': 'a', 'State': 'up'}, {'Name': 'b', 'State': 'down'}, {'Name': 'c', 'State': 'up'}]
Functions
JMESPath includes built-in functions for transformations. Input
{
"test": {
"people": [
{"name": "b", "age": 30},
{"name": "a", "age": 50},
{"name": "c", "age": 40}
]
}
}
Queries and results:
- Count people:
{{ test | json_query("length(people)") }}
Result: 3
- Find the oldest person:
{{ test | json_query("max_by(people, &age).name") }}
Result: a
- Sum all ages:
{{ test | json_query("sum(people[].age)") }}
Result: 120
Best Practices for JMESPath in APIO
- Use
| tojson
for Output: Always serialize your results for compact output. - Test Expressions: Validate your queries with simple JSON inputs.
- Chain Queries: Use pipe expressions to streamline data extraction.