Query Templates
Query templates enable dynamic and reusable query definitions. They allow you to create parameterized search request bodies, query string parameters, and HTTP headers to which the queries in a query set can be applied to generate requests for endpoints.
What are Query Templates?
Query templates are based on Mustache / Handlebars templating syntax, which supports:
- Variable substitution using the
{{variable}}syntax - Conditional logic, such as
{{#if variable}}variable exists{{/if}} - Iteration over collections using
{{#each collection}}{{/each}}
Anatomy of a Query Template
A query template consists of the following main properties:
- Body Template: Defines the structure of the HTTP request body
- Body Content Type: Defines the output content type of the body template
- Query String Template: Defines the URL query string parameters
Example
The following is an example of defining an Elasticsearch query with a query template.
Firstly, define the query string parameters
{{size}}controls the number of hits to return{{explain}}controls whether to include the detailed information about score computation as part of a hit
Secondly, define the request body
{{query}}is the search input{{minimum_should_match}}controls the minimum number of terms a document must match to be returned in search results
Putting this all together into a query template request:
In this example:
{{size}}and{{from}}are variables in the query string parameters for pagination{{query}}is a variable in the body that will be replaced with the actual search term
Common Handlebars syntax
The following sections highlight the most common handlebars syntax you're likely to use. For more details, consult the Handlebars and Mustache documentation.
@data variables
@data variables are implemented by Handlebars and built-in helpers. They have values in specific contexts:
@data variable | description |
|---|---|
@root | Initial context with which the template is executed. |
@first | Set to true by the {{#each}} helper for the first iteration |
@last | Set to true by the {{#each}} helper for the last iteration |
@index | Set to the zero-based index of the current iteration by the {{#each}} helper |
@key | Set to the key name of the current iteration by the {{#each}} helper when iterating over objects |
Variables
A variable expression is a name enclosed within double braces. The most common is
which represents a query from a query set, as either a text string of search
terms, or the "query" property in a query JSON object.
Variables are encoded/escaped based on the context:
- In a query string, they are URL encoded
- In a text request body, they are not encoded
- In a JSON request body, they are JSON encoded
If you don't want a variable to be encoded/escaped, enclose it in triple braces
Conditions
If Condition
Branching logic can be expressed with the {{#if}} block helper function:
If size is a truthy value i.e. not false, undefined, null, "", 0 or [], then
the value enclosed in the block will be rendered.
For query
{ "query": "The Godfather", "size": 20 }
this renders
size=20
but the following query
{ "query": "The Godfather" }
renders an empty string.
An else branch can be used to provide a default value, using {{else}} inside the body
of an {{#if}} block:
which for the latter query, now renders
size=10
Unless Condition
The {{#unless}} condition can be considered the inverse of the {{#if}} condition; if the
expression is a falsy value i.e. false, undefined, null, "", 0 or [], then
the value enclosed in the block will be rendered.
The previous {{else}} branch could be written more verbosely as
Iteration
Iteration can be expressed with the {{#each}} block helper function:
{{this}} inside the {{#each}} block represents the item in the current iteration.
Iteration can be used to template complex queries:
which for the following query
{ "query": "The Godfather", "field": ["title", "description", "actors"] }
renders
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "the Godfather"
}
},
{
"match": {
"description": "the Godfather"
}
},
{
"match": {
"actors": "the Godfather"
}
}
]
}
}
}
toJSON block helper
The {{#toJson}} block helper function provides a powerful way to incorporate raw JSON into query templates.
It works similarly to the Mustache helper found in Elasticsearch and OpenSearch,
allowing JSON to be inserted directly into a query template without escaping.
This is particularly useful when you need to include complex nested structures or arrays that would be
cumbersome to construct through standard template syntax.
The name of the query property should be enclosed in the {{#toJson}} block to emit it as JSON:
For example
{ "query": "The Godfather", "genre": ["Crime", "Drama"] }
You could use the toJson helper in your template like this:
which renders
{
"query": {
"bool": {
"should": [
{ "match": { "title": "the Godfather" } }
],
"filter": [
{ "terms": { "genres": ["Crime","Drama"] } }
]
}
}
}