All of the default functionality provided by the jknack Java Handlebars implementation is available.
You can find more information on the Handlebars.java blog or Handlebars.js guide.
We have support for:
- The default string helpers
- The default conditional helpers
- The default number helpers
- Separate template files using partials including template reuse and inheritance
Template files
You can place .hbs files in the installation root directory and
reference them in your primary response template.
This can be useful to either reuse the same template many times, or to organize
response template in separate files, with proper .hbs syntax
highlighting in your editor or IDE.
The syntax
{{>responses/example-response}}
will load the content from the plain text template file responses/example-response.hbs.
The syntax
{{>(stringFormat 'responses/example-response-%s' 'some-value' )}}
allows you to construct the name of the template file dynamically using a string
format for the name of the template file.
You can also pass in parameters to templates:
{{>responses/example-response parameter=1234 }}
or reference parameters that exist already in the surrounding context.
The default file extension is .hbs, you can use a different file extension as follows:
{{>example.txt}}
More advanced usage is possible with template inheritance
which you can use to parameterize blocks in a template:
base.hbs
Something before
{{#block "content"}}
Some default content
{{/block}}
Something after
override.hbs:
{{#partial "content" }}
Some override content
{{/partial}}
{{> base}}
WireMock helpers
The following WireMock Handlebars helpers are available for use.
- {{xPath request.body '/a/b/text()'}} - Extract XML values or sub documents via XPath
- {{soapXPath request.body '/a/b/text()'}} - Extract SOAP XML values or sub documents via XPath
- {{jsonPath request.body '$.outer.inner'}} - Extract JSON values or sub documents via JSONPath
- {{randomValue length=32 type='ALPHANUMERIC' uppercase=true }} - Generate random strings (also supports mixedcase=true)
- {{pickRandom 'A' 'B' 'C'}} - Pick a random value from a list of alternatives
- {{randomInt lower=1 upper=10}} - Pick a random value in an integer range (lower inclusive, upper exclusive)
- {{randomDecimal lower=1.0 upper=1.5}} - Pick a random value in a decimal range (lower inclusive, upper exclusive)
- {{range -2 2}} - Generate a list of integers
- {{array 1 'string' true}} - Put given values in a list literal
- {{hostname}} - Print the local machine hostname
- {{date (parseDate request.headers.SomeDate format='dd-MM-yyyy')}} - Date parsing
- {{date (truncateDate (parseDate request.headers.SomeDate) 'first day of month')}} - Date truncation
- {{#trim}} text with whitespace {{/trim}} - Remove whitespace
- {{#base64 padding=false decode=false}}content{{/base64}} - Base64 encoding and decoding
- {{#urlEncode decode=false}}content{{/urlEncode}} - URL encoding and decoding
- {{formData request.body 'form' urlDecode=true}}{{form.formField3}} - HTTP form parsing
- {{regexExtract request.body '([a-z]+)-([A-Z]+)-([0-9]+)' 'parts'}}{{parts.0}},{{parts.1}},{{parts.2}} - Regular expression extraction
- {{#if (matches '1234' '[0-9]+')}}OK{{/if}} - Regular expression conditional
- {{#if (contains 'abcde123' 'bcd')}}OK{{/if}} - String or array contains conditional
- {{parseJson request.body 'bodyJson'}}{{bodyJson.name}} - Parse string into a named JSON object
- {{size request.query.things}} - Number of elements in a string/list/map
- {{systemValue type='ENVIRONMENT' key='wiremock.VARIABLE'}} - Use system properties or environment variables
- {{#assign 'name'}}value{{/assign}} - Set a string variable with assign block
- {{val 1234 assign='numberVar'}} - Set a variable of any type with val (preserves type, unlike assign which always stores strings)
- {{val request.query.example or='default'}} - Get a variable with a default value
- {{lookup object 'field'}} - Object field lookup
- {{arrayAdd (array 'example1' 'example2') 'example-middle' position=1}} - Array element add
- {{arrayRemove (array 'example1' 'middle' 'example2') position=1}} - Array element remove
- {{arrayJoin ',' (array '1' '2' '3')}} - Array join with separator
- {{formatJson jsonObject}} - Format JSON in pretty or compact form (supports format='compact')
- {{formatXml xmlString}} - Format XML in pretty or compact form (supports format='compact')
- {{toJson someObject}} - Convert any object to a JSON string
- {{jsonMerge json1 json2}} - Merge two JSON objects recursively (supports removeNulls=true)
- {{jsonRemove jsonString jsonPath='$.field'}} - Remove elements from JSON by JSON path
- {{jsonArrayAdd existingJson jsonPath='$.items' newItem}} - Add items to a nested JSON array
The following WireMock Handlebars helpers have alternatives in Traffic Parrot.
- {{math}} - See Arithmetic operations
- {{now}} - See Transform strings and Date offset
- The default implementation of {{now}} can be toggled using trafficparrot.properties
-
Alternatively, you can add the provider parameter per call to dynamically switch between them, otherwise the default implementation specified in trafficparrot.properties will be used
- To enable this set in trafficparrot.properties:
trafficparrot.virtualservice.handlebars.now.dynamic=true
- To use the Handlebars.java implementation:
{{now format='short' provider='HANDLEBARS'}}
- To use the WireMock implementation:
{{now offset='2 years' format='epoch' provider='WIREMOCK'}}
WireMock JWT helpers
The JWT Extension for WireMock is supported.
JWT usage examples, typically mocked via an /oauth/token endpoint:
{{jwt maxAge='12 days'}}
{{jwt exp=(parseDate '2041-02-23T21:22:23Z')}}
{{jwt nbf=(parseDate '2019-02-23T21:22:23Z')}}
{{jwt iss='https://issuer.trafficparrot.com/'}}
{{jwt aud='https://audience.trafficparrot.com/'}}
{{jwt sub='subject'}}
{{jwt alg='RS256'}}
{{jwt
customBoolClaim=true
customIntClaim=23
customStringClaim='example@x.y.z'
customDateClaim=(parseDate '2024-01-02T03:04:05Z')
}}
JSON Web Key Set (JWKS) usage example, typically mocked via an /.well-known/jwks.json endpoint:
{{jwks}}
Settings also visible via http://localhost:8080/api/http/__admin/settings as:
{
"settings" : {
"extended" : {
"jwt" : {
"hs256Secret" : "...",
"rs256PublicKeyId" : "...",
"rs256PublicKey" : "-----BEGIN RSA PUBLIC KEY-----\n...\n-----END RSA PUBLIC KEY-----\n",
"rs256PrivateKey" : "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n"
}
}
}
}
Enable in trafficparrot.properties by setting:
trafficparrot.http.jwt.enabled=true
All of jknack Handlebars string helpers are available for use in both HTTP and JMS response headers and body.
- {{defaultIfEmpty value ["default value"]}} - Render a default value if the specified value is not available, for example {{defaultIfEmpty request.query.username "Username parameter was not present in the request"}}
- {{substring value start end}} - Render the beginning of the string value, for example {{defaultIfEmpty request.query.username 0 3}}
- {{substring value start}} - Render the end of the string value, for example {{defaultIfEmpty request.query.username 5}}
- {{replace value "aaa" "bbb"}} - Replace string aaa with bbb
- {{abbreviate value 5}} - Render a truncated version of a string. Minimum value is 4.
- {{yesno value [yes="yes"] [no="no"] maybe=["maybe"]}} - Convert a boolean "true", "false" to a string representation
- {{capitalize value [fully=false]}} - Capitalize a string
- {{stripTags value}} - Remove all HTML or XML tags from the string
- {{stringFormat string param0 param1 ... paramN}} - Format the string
- {{slugify value}} - Create a slug, for example "a b c" will be rendered as "a-b-c"
- {{numberFormat number ["format"] [locale=default]}} - Format a number for a given locale or format
- {{now ["format"] [tz=timeZone|timeZoneId]}} - Date is a specified format and timezone
- {{upper value}} - Uppercase string
- {{lower value}} - Lowercase string
- {{rjust value 20 [pad=" "]}} - Right adjust string
- {{ljust value 20 [pad=" "]}} - Left adjust string
- {{cut value [" "]}} - Cut out all the occurrences in the string
- {{center value size=19 [pad="char"]}} - Center string value padded with the specified character
- {{capitalizeFirst value}} - Capitalize first word
- {{join value "," [prefix="aPrefix"] [suffix="aSuffix"]}} - Join an array of values
Arithmetic operations
The math helper can be used to perform arithmetic operations:
- {{math a "+" b}} - Addition
- {{math a "-" b}} - Subtraction
- {{math a "*" b}} - Multiplication
- {{math a "/" b}} - Division
- {{math a "%" b}} - Modulus
- {{math "-" x}} - Negate
- {{math "round" x}} - Round
Supported options:
- scale=N - the result will have N digits to the right of the decimal point
Modify response
The {{ modifyResponse }} helper can be used to modify the:
- response HTTP status code
- response header values
Examples:
- Modify the response status code:
{{ modifyResponse 'statusCode' 404 }}
- Modify the response status code conditionally:
{{#contains request.body 'A'}}
{{ modifyResponse 'statusCode' 400 }}
{{else contains request.body 'B'}}
{{ modifyResponse 'statusCode' 500 }}
{{else}}
{{ modifyResponse 'statusCode' 200 }}
{{/contains}}
- Modify a header value:
{{ modifyResponse 'headerValue' 'header-name' 'header-value' }}
Convert data type
The {{ cast }} helper can be used to convert between data types.
Examples:
- {{ cast value type='int' }} - convert value to an int
- {{ cast list type='string' }} - convert list of elements to list of strings
- {{ cast list type='string' single=true }} - extract only element from a list and convert to a string type
- {{ randomInteger 0 (cast (xPath request.body '/Node/Max/text()') type='int') }} - example nested usage
- {{#if (cast value type='boolean') }}value cast to true{{/if}} - example if conditional usage
- {{#if (not (cast value type='boolean') ) }}value cast to false{{/if}} - example if not conditional usage
- {{#unless (cast value type='boolean') }}value cast to false{{/unless}} - example unless conditional usage
Supported options:
- single=true - extract only element from a single element list
- type='string' - convert to string representation
- type='long' - convert to long
- type='int' - convert to int
- type='short' - convert to short
- type='double' - convert to float
- type='float' - convert to double
- type='boolean' - convert to boolean
When casting to boolean, the semantics are:
- The string 'true' casts to boolean true
- The string 'false' casts to boolean false
- Blank strings like '' or ' ' cast to boolean false
- Empty collections cast to boolean false
- Non-empty collections cast to boolean true
- The number zero casts to boolean false
- Non-zero numbers cast to boolean true
Date offset
The {{ dateOffset }} helper can be used to calculate an offset from a given date.
This can be combined with extracting data from the request to
dynamically offset a date in the response based on a date in the request.
Examples:
- {{ dateOffset "2018-07-09" add=true format="yyyy-MM-dd" days=1 }} - add 1 day to the given date
- {{ dateOffset "2017-10-31T16:16:10" inFormat="yyyy-MM-dd'T'HH:mm:ss" outFormat="yyyy-MM-dd'T'HH:mm:ssZ" zone="America/Los_Angeles" days=1 hours=4 }} - subtract 1 day and 4 hours from given local date and reformat as a timestamp in time zone
Supported options:
- add=true - add to the input date rather than the default of subtracting
- format="yyyy-MM-dd" - specify a date format for both parsing and formatting using standard date and time formatting options
- inFormat="yyyy-MM-dd" - specify a date format for parsing using standard date and time formatting options
- outFormat="yyyy-MM-dd" - specify a date format for formatting using standard date and time formatting options
- zone="UTC" - specify a time zone ID for both parsing and formatting e.g. America/Los_Angeles or UTC or -08:30
- inZone="UTC" - specify a time zone ID for parsing e.g. America/Los_Angeles or UTC or -08:30
- outZone="UTC" - specify a time zone ID for formatting e.g. America/Los_Angeles or UTC or -08:30
- days=1 - number of days to offset by
- minutes=1 - number of minutes to offset by
- seconds=1 - number of seconds to offset by
- millis=1 - number of milliseconds to offset by
- nanos=1 - number of nanoseconds to offset by
Data source
The {{ dataSource }} helper can be used to query or update an existing data source using a SQL style syntax.
This can be combined with extracting data from the request to
dynamically select a response field or update state for later use.
Currently supported data source features:
| Source |
CREATE |
SELECT |
INSERT |
UPDATE |
DELETE |
Caching |
Batch Update |
Multiple Results |
Multiple Conditions |
Default Values |
| CSV |
|
|
|
|
|
|
|
|
|
|
| XLS |
|
|
|
|
|
|
|
|
|
|
| JDBC |
|
|
|
|
|
|
|
|
|
|
| Couchbase1 |
|
|
|
|
|
|
|
|
|
|
1 Couchbase uses N1SQL aka SQL++ statements which also includes other operations such as UPSERT and MERGE
Please contact us if you
require any data source operation compatibility that is not currently available.
Examples:
-
Select a single value from data/isoCountryCodes.csv or default to GBR:
{{ dataSource '.csv'
'SELECT isoCountryCode
FROM isoCountryCodes.csv
WHERE internalCode = :1'
(jsonPath request.body '$.internalCode')
single=true
default='GBR' }}
-
Select multiple rows and columns from the JDBC database with id example.db:
[
{{#each (dataSource 'example.db' 'SELECT * FROM table') }}
{
"A": {{ A }},
"B": {{ B }}
}{{#unless @last}},{{/unless}}
{{/each}}
]
-
Insert single record into the JDBC database with id example.db:
{{ dataSource 'example.db'
'INSERT INTO PERSON(ID, NAME) VALUES(:id, :name)'
id=(jsonPath request '$.id')
name=(jsonPath request '$.name') }}
-
Insert multiple records into the JDBC database with id example.db:
{{ dataSource 'example.db'
'INSERT INTO PERSON(ID, NAME) VALUES(:ids, :names)'
ids=(jsonPath request '$.data[*].id')
names=(jsonPath request '$.data[*].name') }}
-
Select multiple columns and single row from XLS file data/example.xlsx and sheet ExampeSheet:
{{#with (dataSource 'example.xlsx' 'SELECT * FROM ExampleSheet' singleRow=true ) }}
{
"A": {{ A }},
"B": {{ B }}
}
{{/with}}
-
Select single value using positional argument :1
{{dataSource 'example.xlsx'
'SELECT name
FROM ExampleSheet
WHERE id = :1'
(jsonPath request.body '$.id')
single=true }}
-
Select single value using named argument :id
{{dataSource 'example.xlsx'
'SELECT name
FROM ExampleSheet
WHERE id = :id'
id=(jsonPath request.body '$.id')
single=true }}
Supported options:
- single=true - extract single row single column result
- singleRow=true - extract single row result
- maxRows=N - limit number of rows returned
- default=value - provide default value to be used on error or no result
- shared=true - use configuration from installation root when true or configuration from scenarios/ScenarioName/* when false
Further details on the specifics of each data source can be found below.
CSV
- The .csv files should be placed in the data directory
- To configure caching of CSV files for improved performance use the propertytrafficparrot.virtualservice.handlebars.select.indexAndCacheCsvFiles=true
- Column names must be defined in the first row
XLS
- The .xls or .xlsx files should be placed in the data directory
- Sheet names are used as the "table" to select from
- Column names must be defined in the first row
JDBC
-
Supported databases include:
- MySQL
- MariaDB
- PostgreSQL
- Oracle
- Microsoft SQL Server MSSQL
- and any other database that has a JDBC driver
- The database driver JAR must be placed in the lib/external/*.jar directory
- The database schema and tables must already exist before attempting to use as a data source
-
The database connection should be defined in the database-connections.json file, for example:
[
{
"connectionId": "example.db",
"type": "JDBC_CONNECTION",
"driverClass": "org.h2.Driver",
"jdbcUrl": "jdbc:h2:mem:example",
"properties": {
"user": "sa",
"password": "sa"
}
},
{
"connectionId": "postgres.db",
"type": "JDBC_CONNECTION",
"driverClass": "org.postgresql.Driver",
"jdbcUrl": "jdbc:postgresql://host:port/database",
"properties": {
"user": "user",
"password": "password"
}
}
]
Couchbase
- The following Couchbase SDK JARs must be placed in the lib/external/*.jar directory:
- The bucket must already exist before attempting to use as a data source
-
The database connection should be defined in the database-connections.json file, for example:
[
{
"connectionId": "couchbase.db",
"type": "COUCHBASE_CONNECTION",
"connectionString": "couchbase://localhost:32784",
"username": "Administrator",
"password": "password",
"warmupQuery": "SELECT COUNT(*) FROM bucket_a UNION SELECT COUNT(*) FROM bucket_b",
"enableDnsSrv": true,
"networkResolution": "auto"
}
]
- Couchbase uses N1SQL aka SQL++ statements in the following syntax:
{{ dataSource 'couchbase.db' 'INSERT INTO PERSON(KEY, VALUE) VALUES ("$id", {"id" : $id,"name" : $name})' id=1000 name='some-name' syntax='N1QL' }}
{{ dataSource 'couchbase.db' 'SELECT name FROM PERSON USE KEYS "$id"' id=1000 single=true syntax='N1QL' }}
{{ dataSource 'couchbase.db' 'INSERT INTO PERSON(KEY, VALUE) VALUES ("$id", $object)' id=1000 object=example syntax='N1QL' }}
- You can control query scan consistency using the scanConsistency parameter:
- scanConsistency='REQUEST_PLUS' - consistent results, waits for all pending mutations to be indexed (default)
- scanConsistency='NOT_BOUNDED' - faster queries, results may not include the most recent mutations
For example:
{{ dataSource 'couchbase.db' 'SELECT name FROM PERSON USE KEYS "$id"' id=1000 single=true syntax='N1QL' scanConsistency='NOT_BOUNDED' }}
- Couchbase queries that fail due to a missing document return an empty result, which can be handled using default='' for clean conditional logic. Other Couchbase errors (e.g. syntax errors or connection issues) return an error message instead of throwing an exception. You can use the default option to provide a fallback value.
Object store
The {{ objectStore }} helper can be used to query or update a JSON object.
This can be combined with extracting data from the request to
manage simple persistent object state across requests.
Examples:
-
Create a new object in data/person-uuid.json using the incoming JSON request body and unique id:
{{ objectStore 'person.json' operation='create' id=(jsonPath request.body '$.id') object=request.body }}
-
Create a new object in data/person-uuid.json using the incoming JSON request body and generated unique id:
{{#trim}}
{{#with (randomValue type='UUID') }}
{{ objectStore 'person.json' operation='create' id=. object=request.body }}
{{ objectStore 'person.json' operation='put' id=. path='$' key='id' object=. }}
{{ objectStore 'person.json' operation='get' id=. path='$' }}
{{/with}}
{{/trim}}
-
Get an existing object stored in data/person-uuid.json:
{{ objectStore 'person.json' operation='get' id=(jsonPath request.body '$.id') path='$' }}
-
Get a particular field from an existing object stored in data/person-1.json:
{{ objectStore 'person.json' operation='get' id=(jsonPath request.body '$.id') path='$.field' }}
-
Set an existing field to the value of a field in the request:
{{ objectStore 'person.json' operation='set' id=(jsonPath request.body '$.id') path='$.field' object=(jsonPath request.body '$.field') }}
-
Delete an existing field:
{{ objectStore 'person.json' operation='delete' id=(jsonPath request.body '$.id') path='$.field' }}
-
Delete entire object:
{{ objectStore 'person.json' operation='delete' id=(jsonPath request.body '$.id') path='$' }}
-
Add or update a field at the root of the object:
{{ objectStore 'person.json' operation='put' id=(jsonPath request.body '$.id') path='$' key='field' object=(jsonPath request.body '$.field') }}
-
Add or update a field at a child of the object:
{{ objectStore 'person.json' operation='put' id=(jsonPath request.body '$.id') path='$.child' key='field' object=(jsonPath request.body '$.child.field') }}
-
Add an element to an existing array:
{{ objectStore 'person.json' operation='add' id=(jsonPath request.body '$.id') path='$.names' object=(jsonPath request.body '$.name') }}
Supported options:
- operation='name' - supported operations are: create, get, set, delete, add, put
- overwrite=true - allows the create operation to overwrite an existing object when true
- id='' - a unique id must be provided to identify the object
- default=null - if specified, the provided default value will be returned if an object is not found with the given id
- path='$' - a JSONPath expression used by the operation
- object='' - a JSON object used by the operation
- key='' - the name of the new field to be added by the put operation
- shared=true - use configuration from installation root when true or configuration from scenarios/ScenarioName/* when false
Manage state
The {{ manageState }} helper can be used to manage simple key-value state across requests.
You can set a value in one response and retrieve it in a subsequent response, enabling stateful mock behaviour.
State can be organized into namespaces using the namespace/variableName syntax.
If no namespace is specified, the variable is stored in the global namespace.
This matches the namespace convention used by the
state management REST API.
Operations:
-
Set a global variable:
{{ manageState 'counter' 'set' 1234 }}
-
Get a global variable:
{{ manageState 'counter' 'get' }}
-
Increment a global variable by a numeric value:
{{ manageState 'counter' '+' 1 }}
-
Set a variable in a specific namespace:
{{ manageState 'scenario-1/counter' 'set' 42 }}
-
Get a variable from a specific namespace:
{{ manageState 'scenario-1/counter' 'get' }}
-
Increment a variable in a specific namespace:
{{ manageState 'scenario-1/counter' '+' 1 }}
-
Use a custom separator (default is /):
{{ manageState 'scenario-1::counter' 'get' separator='::' }}
Variables in different namespaces are isolated from each other.
For example, scenario-1/counter and scenario-2/counter
are independent variables.
Variables without a namespace prefix (e.g. counter) use the
global namespace and can be accessed via the REST API at
GET /api/state/global/counter.
Namespaced variables can be accessed via the REST API at
GET /api/state/{namespace}/{name}, for example
GET /api/state/scenario-1/counter.
You can also reset all state using DELETE /api/state
or clear a single namespace using DELETE /api/state/{namespace}.
Evaluate
The {{ evaluate }} helper can be used to evaluate an expression in a scripting language such as JavaScript.
NOTE: this requires a scripting engine such as Nashhorn
or GraalVM to be installed, either as part of the JRE or placed in the lib/external/*.jar directory.
Examples:
-
Complex boolean expression:
{{ evaluate '/[0-9]+/.test(request.headers["request-id"]) && JSON.parse(request.body)["name"].contains("123123")' }}
-
Using if statements:
{{#evaluate}}
if (key === 123) {
'hello world 123'
} else {
'hello non 123 world'
}
{{/evaluate}}
-
Render current epoch time:
{{ evaluate 'new Date().getTime()' }}
-
Render using print statement:
{{ evaluate 'print("hello world print")'}}
Supported options:
- language='js' - currently only js is supported, which is also the default
- redirectOutput='RESULT' - RESULT will enable print statements LOGS will suppress print statements from the result and instead put them in the Traffic Parrot logs
Supported context items:
- Use the keyword self to reference the current context object:
{{#with 'test' }}{{ evaluate 'self' }}{{/with}}
- Use the name of any context variable to reference it:
{{ evaluate 'name' }}
- Use the syntax parameters[i] to reference parameters by index:
{{ evaluate 'parameters[2]' 'zero' 'one' 'two' }}
- Use the syntax options["name"] to reference named options by name:
{{ evaluate 'options["example"]' example='value' }}
The following additional helpers are available in HTTP, JMS, IBM MQ and File response templates.
You can use it to extract a value from a field using an XPath.
Syntax:
{{xPath sourceAttribute 'TheXPathValue'}}
For example, if you use the following handlebar in a HTTP response body:
Request foobar value was: {{xPath request.body '/foo/bar/text()'}}
and then send a HTTP request:
<foo><bar>Long live mocking!</bar></foo>
you will see a HTTP response:
Request foobar value was: Long live mocking!
xPathList
You can use it to extract a list of nodes from a field using an XPath.
Can be combined with loop iterators to transform a request body.
Syntax:
{{xPathList sourceAttribute 'TheXPathValue'}}
For example, if you use the following handlebar in a HTTP response body:
<items>
{{#each (xPathList request.body '/request/items') }}
<item id="{{ xPath this '/item/@id' }}" status="OK">{{ xPath this '/item/text()' }}</item>
{{/each}}
</items>
and send a HTTP request:
<request>
<items>
<item id="one" ignored="any">body1</item>
<item id="two" ignored="any">body2</item>
</items>
</request>
you will see a HTTP response:
<items>
<item id="one" status="OK">body1</item>
<item id="two" status="OK">body2</item>
</items>
You can use it to extract a value from a field using an JsonPath.
Syntax:
{{jsonPath sourceAttribute 'TheJsonPathValue'}}
For example, if you use the following handlebar in a HTTP response body:
Request foobar value was: {{jsonPath request.body '$.foo.bar'}}
and then send a HTTP request:
{"foo":{"bar":"Long live mocking!"}}
you will see a HTTP response:
Request foobar value was: Long live mocking!
You can also use JsonPath conditional expressions, for example to check for the presence of a field:
{{#if (jsonPath request.body '$.[?(@.field)]') }}field is present{{/if}}
{{#if (not (jsonPath request.body '$.[?(@.field)]') ) }}field is not present{{/unless}}
{{#if (jsonPath request.body '$.[?(!(@.field))]') }}field is not present{{/unless}}
{{#unless (jsonPath request.body '$.[?(@.field)]') }}field is not present{{/unless}}
jsonPathList
You can use it to extract a list of values from a field using an JsonPath.
Can be combined with loop iterators to transform a request body.
Syntax:
{{jsonPathList sourceAttribute 'TheJsonPathValue'}}
For example, if you use the following handlebar in a HTTP response body:
[
{{#each (jsonPathList request.body '$.items') }}
{ id: {{ jsonPath this '$.id' }}", status: "OK" }{{#unless @last}},{{/unless}}
{{/each}}
]
and send a HTTP request:
{
items: [
{ id: 1234, ignored: "any" },
{ id: 1235, ignored: "any" }
]
}
you will see a HTTP response:
[
{ id: 1234, status: "OK" },
{ id: 1235, status: "OK" }
]
You can use it to extract a value from a field using a single regular expression capturing group.
Syntax:
{{regex sourceAttribute 'TheRegex(.*)Value'}}
For example, if you use the following handlebar in a HTTP response body:
Request value was: {{regex request.body '.+? ([0-9A-Za-z]+Camel-[0-9A-Za-z]+).*'}}
and then send a HTTP request:
before 001116059c5549a0tOACamel-116059c554a20tOH after
you will see a HTTP response:
Request value was: 001116059c5549a0tOACamel-116059c554a20tOH
You can use it to extract a field value from a SWIFT MT message by its tag number.
This is useful when creating dynamic responses that reference specific fields from a SWIFT message request body.
Syntax:
{{swiftField sourceAttribute 'TagNumber'}}
For example, if you use the following handlebar in a response body:
Transaction reference: {{swiftField request.body '20'}}
and then send a request with a SWIFT MT103 message body:
{1:F01BANKBEBBAXXX0000000000}{2:I103BANKDEFFXXXXN}{4:
:20:TXNREF001
:23B:CRED
:32A:230101EUR1000,00
:50K:/1234567890
ACME CORP
:59:/9876543210
BENEFICIARY NAME
123 MAIN STREET
LONDON
:71A:SHA
-}
you will see a response:
Transaction reference: TXNREF001
The helper also works with bare Block 4 content (without the SWIFT envelope blocks).
For example:
{{swiftField request.body '59'}}
applied to:
:20:REF001
:59:/9876543210
BENEFICIARY NAME
123 MAIN STREET
LONDON
:71A:SHA
returns the full multi-line value:
/9876543210
BENEFICIARY NAME
123 MAIN STREET
LONDON
If the specified tag is not present, or if the input is not a SWIFT message, the helper returns an empty string.
If the tag appears multiple times, the first occurrence is returned.
Nested handlebars helpers
You can call helpers inside other helpers. You just have to wrap them in parenthesis.
For example, if you use the following handlebar in a HTTP response body:
Bar was equal to xxx: {{#equal (jsonPath request.body '$.foo.bar') 'xxx'}}true{{else}}false{{/equal}}'
and then send a HTTP request:
{"foo":{"bar":"xxx"}}
you will see a HTTP response:
Bar was equal to xxx: true