--- title: Response Templates description: Generate dynamic mock responses using Mustache, Velocity, or JavaScript templates with access to request data, UUIDs, timestamps, and helper objects. layout: page pageOrder: 3 section: 'Creating Mocks' subsection: true sitemap: priority: 0.8 changefreq: 'monthly' lastmod: 2026-06-24T00:00:00+00:00 ---
A static mock always returns the same body regardless of what the client sent. Response templates let the mock react to the incoming request — echoing a request field back in the response, generating a unique ID, or returning different data depending on a query parameter. This makes a single expectation cover an entire family of requests without enumerating every combination.
For example, a Mustache template can echo the requested user ID straight back in the response body:
new ClientAndServer(1080)
.when(
request()
.withPath("/users/{id}")
)
.respond(
template(
HttpTemplate.TemplateType.MUSTACHE,
"{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}"
)
);
var mockServerClient = require('mockserver-client').mockServerClient;
mockServerClient("localhost", 1080).mockAnyResponse({
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}).then(
function () {
console.log("expectation created");
},
function (error) {
console.log(error);
}
);
See REST API for full JSON specification
from mockserver.client import MockServerClient
from mockserver.models import Expectation
client = MockServerClient("localhost", 1080)
client.upsert(Expectation.from_dict({
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}))
require 'mockserver-client'
client = MockServer::Client.new('localhost', 1080)
client.upsert(MockServer::Expectation.from_hash({
'httpRequest' => {
'path' => '/users/{id}'
},
'httpResponseTemplate' => {
'template' => "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
'templateType' => 'MUSTACHE'
}
}))
package main
import (
"bytes"
"net/http"
)
func main() {
body := []byte(`{
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}`)
req, _ := http.NewRequest("PUT",
"http://localhost:1080/mockserver/expectation",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
using System.Net.Http;
using System.Text;
using var httpClient = new HttpClient();
var json = @"{
""httpRequest"": {
""path"": ""/users/{id}""
},
""httpResponseTemplate"": {
""template"": ""{\""id\"": \""{{request.pathParameters.id.[0]}}\"", \""name\"": \""User {{request.pathParameters.id.[0]}}\""}"",
""templateType"": ""MUSTACHE""
}
}";
await httpClient.PutAsync(
"http://localhost:1080/mockserver/expectation",
new StringContent(json, Encoding.UTF8, "application/json")
);
use reqwest::blocking::Client;
let client = Client::new();
let body = r#"{
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}"#;
client.put("http://localhost:1080/mockserver/expectation")
.header("Content-Type", "application/json")
.body(body.to_string())
.send()
.unwrap();
$json = <<<'JSON'
{
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}
JSON;
$ch = curl_init('http://localhost:1080/mockserver/expectation');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json; charset=utf-8'],
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
curl_close($ch);
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"path": "/users/{id}"
},
"httpResponseTemplate": {
"template": "{\"id\": \"{{request.pathParameters.id.[0]}}\", \"name\": \"User {{request.pathParameters.id.[0]}}\"}",
"templateType": "MUSTACHE"
}
}'
See REST API for full JSON specification
Templates are evaluated at request time, so the response is always fresh. See the sections below for the full template format reference, available variables, and helper objects.
The same templating also applies to streaming responses: set a templateType on an httpSseResponse or httpWebSocketResponse (or per-message on a gRPC stream response) and each event/message payload is rendered as a response template against the request, using the same variables and helpers described here. See SSE & WebSocket mocking.
MockServer supports dynamic response templates that generate responses based on request data, built-in variables, and helper objects. The following template features are supported:
graaljs Docker image variant or adding GraalVM Polyglot dependencies to the classpath)templateFileFILE response body as a template with templateTypeResponseTemplateTesterjavascriptAllowedClasses or velocityDisallowClassLoadingThe table below is a one-look index of every template feature on this page. Click the link in the Section column to jump straight to the reference.
| Feature / Object | What it provides | Section |
|---|---|---|
| Template Formats | ||
| Mustache | Logic-less templates with sections, loops, JsonPath, and XPath extraction | Mustache Templates |
| Velocity | Apache Velocity engine — conditionals, loops, math, JSON/XML body parsing | Velocity Templates |
| JavaScript | Full ES2023+ via GraalVM Polyglot — requires the graaljs image variant |
JavaScript Templates |
| Template Sources | ||
| Templates in JSON Files | Embedding templates in JSON initializer files; newline escaping rules | Templates in JSON Initializer Files |
| Templates from Files | Reference a template stored in a file with templateFile |
Loading Templates From Files |
| Body File Templating | Render a FILE response body as a Mustache or Velocity template |
Templating A Response Body File |
| Template Testing | Test templates locally with ResponseTemplateTester |
Response Template Testing |
| Request Variables | ||
| Request Model Variables | Access method, path, headers, cookies, body, remoteAddress, and more | Request Model Variables |
| Multi-Value Maps | Access headers, path parameters, and query parameters by key, entry set, values, or key set | Multi-Value And Single Value Maps |
| Built-in Dynamic Variables | ||
| Dynamic Variables | Timestamps (now_iso_8601, now_epoch, now_rfc_1123), UUID, random integers, random bytes |
Dynamic Model Variables |
| Helper Objects | ||
jwt |
Generate signed JWTs and JWKS for testing OAuth2/OIDC flows | JWT Helper |
strings |
Trim, capitalize, URL/Base64 encode/decode, substring, replace, length, contains | String Helper |
jsonTransform |
Merge, sort, extract fields, add/remove elements, pretty-print JSON strings | JSON Transform Helper |
dates |
Date formatting, arithmetic (plus/minus seconds/minutes/hours/days), epoch conversion | Date Helper |
calc |
Random numbers, rounding, min/max, abs, ceil/floor, number formatting | Calc Helper |
faker |
Realistic fake data — names, addresses, emails, phone numbers, 250+ categories | Faker Helper |
crypto |
MD5, SHA-1, SHA-256, SHA-512 digests and HMAC-SHA-256 signatures, all as lowercase hex | Crypto Helper |
regex |
Test patterns, capture groups, and replace substrings using Java regex | Regex Helper |
html |
Escape and unescape HTML entities (HTML 4.0) | HTML Helper |
csv |
Parse CSV text into rows and format a row back to CSV (RFC 4180) | CSV Helper |
xpath |
Evaluate an XPath expression against an XML document (XXE-safe) | XPath Helper |
yaml |
Convert YAML to JSON and read a top-level field from a YAML document | YAML Helper |
| Security | ||
| Security Considerations | Java class access is blocked by default; grant it via javascriptAllowedClasses / velocityDisallowClassLoading |
Security Considerations |
When defining response templates in JSON expectation initializer files (loaded via MOCKSERVER_INITIALIZATION_JSON_PATH), newlines within template strings must be represented as \\n because JSON does not support multi-line string values. For example:
{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"templateType": "MUSTACHE",
"template": "{ 'statusCode': 200, 'body': 'line1\\nline2' }"
}
}
Complex multi-line templates can become difficult to read and maintain in JSON format. For templates with significant logic or formatting, consider using a class-based ExpectationInitializer instead. A Java class initializer allows you to define templates as normal multi-line strings and provides full IDE support for editing and debugging.
See initializing expectations for details on both JSON and class-based initializers.
Instead of embedding the template inline, the template can be stored in a separate file and referenced with templateFile (a path resolved from the classpath or the filesystem). This keeps large templates out of the expectation JSON and lets you edit them with proper syntax highlighting. If both template and templateFile are provided, the inline template takes precedence.
{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"templateType": "MUSTACHE",
"templateFile": "templates/some_response.mustache"
}
}
The same templateFile option is available on httpForwardTemplate for templated request forwarding.
A static response can already serve its body from a file using a FILE body (see creating expectations). To make that file dynamic, add a templateType of MUSTACHE or VELOCITY — the file contents are then rendered as a template against the request before being returned as the response body. The status code, headers, and content type still come from the static response, while only the body file is templated:
{
"httpRequest": {
"path": "/some/path"
},
"httpResponse": {
"statusCode": 200,
"body": {
"type": "FILE",
"filePath": "responses/order.json",
"templateType": "MUSTACHE",
"contentType": "application/json"
}
}
}
With the body file responses/order.json containing template placeholders, for example:
{% raw %}{ "method": "{{ request.method }}", "path": "{{ request.path }}" }{% endraw %}
Body-file templating uses the text-based engines (MUSTACHE and VELOCITY) because they render text directly. JavaScript templates build a full response object rather than a text fragment, so for JavaScript use an httpResponseTemplate (optionally with templateFile) instead.
To test response templates locally is it possible to use the org.mockserver.templates.ResponseTemplateTester for fast feedback and iteration
mustache templates can be tested locally as follows:
// inputs
String template = "{\n" +
" 'statusCode': 200,\n" +
" 'body': \"{'method': '{{ request.method }}', 'path': '{{ request.path }}', 'headers': '{{ request.headers.host.0 }}'}\"\n" +
"}";
HttpRequest request = request()
.withPath("/somePath")
.withMethod("POST")
.withHeader(HOST.toString(), "mock-server.com")
.withBody("some_body");
// execute
HttpResponse httpResponse = ResponseTemplateTester.testMustacheTemplate(template, request);
// result
System.out.println("httpResponse = " + httpResponse);
velocity templates can be tested locally as follows:
// inputs
String template = "{\n" +
" 'statusCode': 200,\n" +
" 'body': \"{'method': '$request.method', 'path': '$request.path', 'headers': '$request.headers.host[0]'}\"\n" +
"}";
HttpRequest request = request()
.withPath("/somePath")
.withMethod("POST")
.withHeader(HOST.toString(), "mock-server.com")
.withBody("some_body");
// execute
HttpResponse httpResponse = ResponseTemplateTester.testVelocityTemplate(template, request);
// result
System.out.println("httpResponse = " + httpResponse);
javascript templates can be tested locally as follows:
// inputs
String template = "return {\n" +
" 'statusCode': 200,\n" +
" 'body': '{\\'method\\': \\'' + request.method + '\\', \\'path\\': \\'' + request.path + '\\', \\'headers\\': \\'' + request.headers.host[0] + '\\'}'\n" +
"};";
HttpRequest request = request()
.withPath("/somePath")
.withMethod("POST")
.withHeader(HOST.toString(), "mock-server.com")
.withBody("some_body");
// execute
HttpResponse httpResponse = ResponseTemplateTester.testJavaScriptTemplate(template, request);
// result
System.out.println("httpResponse = " + httpResponse);
All templates formats have access to the following request fields
| mustache: | {{ request.method }} |
| velocity: | $!request.method |
| javascript: | request.method |
| mustache: | {{ request.path }} |
| velocity: | $!request.path |
| javascript: | request.path |
| mustache: | {{ request.pathParameters.<key>.<index> }} |
| velocity: | $!request.pathParameters[<key>][<index>] |
| javascript: | request.pathParameters[<key>][<index>] |
pathGroups is 1‑based, so index 0 is the whole match and index 1 is the first capture group, and is empty when the matched path had no capture groups. Path‑parameter {name} captures are exposed via pathParameters instead, so a path mixing {name} templates with regex (...) groups does not populate pathGroups.)
| mustache: | {{ request.pathGroups.<index> }} |
| velocity: | $!request.pathGroups[<index>] |
| javascript: | request.pathGroups[<index>] |
(?<name>...) in the matched path regex, keyed by name; empty when the matched path had no named groups)
| mustache: | {{ request.namedPathGroups.<name> }} |
| velocity: | $!request.namedPathGroups.<name> |
| javascript: | request.namedPathGroups.<name> |
| mustache: | {{ request.queryStringParameters.<key>.<index> }} |
| velocity: | $!request.queryStringParameters[<key>][<index>] |
| javascript: | request.queryStringParameters[<key>][<index>] |
| mustache: | {{ request.headers.<key>.<index> }} |
| velocity: | $!request.headers[<key>][<index>] |
| javascript: | request.headers[<key>][<index>] |
Header name lookup is case-insensitive, as HTTP header names are.
Any casing in the template resolves any casing the client sent on the wire — for example
request.headers.host, request.headers.Host and
request.headers.HOST all read the same header, whether the request arrived over HTTP/1.1
(which keeps the client's casing) or HTTP/2 (which lower-cases header names). This applies to headers only;
cookie, query-string-parameter and path-parameter names remain case-sensitive.
| mustache: | {{ request.cookies.<key> }} |
| velocity: | $!request.cookies[<key>] |
| javascript: | request.cookies[<key>] |
request.body returns the raw request body as a string. To access individual fields within a JSON body, use JsonPath (Mustache), $json.parse() (Velocity), or JSON.parse() (JavaScript) as shown in the examples below.
| mustache: | {{ request.body }} |
| velocity: | $!request.body |
| javascript: | request.body |
| mustache: | {{ request.secure }} |
| velocity: | $!request.secure |
| javascript: | request.secure |
During TLS connections MockServer requests clients to optionally present certificates i.e. optional mTLS.
If the client presents certificates this field is populated with a list of the clients certificates.
Each item in the list contains the following fields:
stringstringstringstringjava.security.cert.X509Certificate| mustache: | {{ request.clientCertificateChain }} |
| velocity: | $!request.clientCertificateChain |
| javascript: | request.clientCertificateChain |
The address of the TCP connection to MockServer; typically the client's address, unless there is a NAT device or load balancer between the client and MockServer.
| mustache: | {{ request.remoteAddress }} |
| velocity: | $!request.remoteAddress |
| javascript: | request.remoteAddress |
True is the client requested HTTP keep alive.
| mustache: | {{ request.keepAlive }} |
| velocity: | $!request.keepAlive |
| javascript: | request.keepAlive |
The request variable contains the follow multi-value maps fields:
request.headersrequest.pathParametersrequest.queryStringParametersThe request variable contains the follow single-value maps fields:
request.cookiesThese multi-value or single-value maps can be accessed in the following ways:
| mustache: | {{ request.headers.<key>.<index> }}{{ request.queryStringParameters.<key>.<index> }}{{ request.headers.<key>.<index> }} |
| velocity: | $!request.pathParameters[<key>][<index>]$!request.queryStringParameters[<key>][<index>]$!request.headers[<key>][<index>] |
| javascript: | request.pathParameters[<key>][<index>]request.queryStringParameters[<key>][<index>]request.headers[<key>][<index>] |
each entry has a key and a value field
for multi-value maps the value is a list
for single-value maps the value is a string
| mustache: | {{ request.pathParameters.entrySet }}{{ request.queryStringParameters.entrySet }}{{ request.headers.entrySet }} |
| velocity: | $!request.pathParameters.entrySet$!request.queryStringParameters.entrySet$!request.headers.entrySet |
| javascript: | not available |
| mustache: | {{ request.pathParameters.values }}{{ request.queryStringParameters.values }}{{ request.headers.values }} |
| velocity: | $!request.pathParameters.values$!request.queryStringParameters.values$!request.headers.values |
| javascript: | for (pathParameterKey in request.pathParameters) {
var values = request.pathParameters[pathParameterKey];
}for (queryStringParameterKey in request.queryStringParameters) {
var values = request.queryStringParameters[queryStringParameterKey];
}for (headerKey in request.headers) {
var values = request.headers[headerKey];
} |
| mustache: | {{ request.pathParameters.keySet }}{{ request.queryStringParameters.keySet }}{{ request.headers.keySet }} |
| velocity: | $!request.pathParameters.keySet$!request.queryStringParameters.keySet$!request.headers.keySet |
| javascript: | for (pathParameterKey in request.pathParameters) {
// ...
}for (queryStringParameterKey in request.queryStringParameters) {
// ...
}for (headerKey in request.headers) {
// ...
} |
All templates formats also have access to the following built-in dynamic variables. They return unique values each time they are used.
Tip: for deterministic testing, you can freeze or control the server clock so that date/time variables (now_iso_8601, now_epoch, now_rfc_1123) and the dates helper return predictable values.
| mustache: | {{ now_iso_8601 }} |
| velocity: | $!now_iso_8601 |
| javascript: | now_iso_8601 |
| mustache: | {{ now_epoch }} |
| velocity: | $!now_epoch |
| javascript: | now_epoch |
| mustache: | {{ now_rfc_1123 }} |
| velocity: | $!now_rfc_1123 |
| javascript: | now_rfc_1123 |
| mustache: | {{ uuid }} |
| velocity: | $!uuid |
| javascript: | uuid |
| mustache: | {{ rand_int_10 }} |
| velocity: | $!rand_int_10 |
| javascript: | rand_int_10 |
| mustache: | {{ rand_int_100 }} |
| velocity: | $!rand_int_100 |
| javascript: | rand_int_100 |
| mustache: | {{ rand_bytes_16 }} |
| velocity: | $!rand_bytes_16 |
| javascript: | rand_bytes_16 |
| mustache: | {{ rand_bytes_32 }} |
| velocity: | $!rand_bytes_32 |
| javascript: | rand_bytes_32 |
| mustache: | {{ rand_bytes_64 }} |
| velocity: | $!rand_bytes_64 |
| javascript: | rand_bytes_64 |
| mustache: | {{ rand_bytes_128 }} |
| velocity: | $!rand_bytes_128 |
| javascript: | rand_bytes_128 |
In addition to the simple dynamic variables above, all template formats have access to helper objects that provide rich functionality for string manipulation, JSON processing, date/time arithmetic, math operations, JWT generation, and realistic fake data generation. These helpers are accessed as objects with methods.
jwt)Generates signed JSON Web Tokens (JWTs) and JSON Web Key Sets (JWKS) for testing OAuth2/OIDC flows. Tokens are signed with RS256 (RSA with SHA-256) using an auto-generated key pair.
| Method | Description | Example Output |
|---|---|---|
jwt.generate() | Generate a JWT with default claims (sub, iss, aud, iat, exp) | eyJhbGciOiJSUzI1NiJ9... |
jwt.generate(claims) | Generate a JWT with custom claims (Velocity/JS only) | eyJhbGciOiJSUzI1NiJ9... |
jwt.jwks() | Return the JWKS (public key set) for verifying tokens | {"keys":[{"kty":"RSA",...}]} |
Usage examples:
{{ jwt }} (generates a default JWT) or {{ jwt.jwks }}$jwt.generate() or $jwt.jwks()jwt.generate() or jwt.jwks()strings)Provides string manipulation functions useful for transforming request data in response templates.
| Method | Description | Example |
|---|---|---|
strings.trim(value) | Remove leading and trailing whitespace | strings.trim(" hello ") → "hello" |
strings.capitalize(value) | Capitalize the first letter | strings.capitalize("hello") → "Hello" |
strings.uppercase(value) | Convert to uppercase | strings.uppercase("hello") → "HELLO" |
strings.lowercase(value) | Convert to lowercase | strings.lowercase("HELLO") → "hello" |
strings.urlEncode(value) | URL-encode a string | strings.urlEncode("a=b") → "a%3Db" |
strings.urlDecode(value) | URL-decode a string | strings.urlDecode("a%3Db") → "a=b" |
strings.base64Encode(value) | Base64-encode a string | strings.base64Encode("hello") → "aGVsbG8=" |
strings.base64Decode(value) | Base64-decode a string | strings.base64Decode("aGVsbG8=") → "hello" |
strings.substringBefore(value, sep) | Get substring before the first occurrence of separator | strings.substringBefore("a-b", "-") → "a" |
strings.substringAfter(value, sep) | Get substring after the first occurrence of separator | strings.substringAfter("a-b", "-") → "b" |
strings.length(value) | Return the length of a string | strings.length("hello") → 5 |
strings.contains(value, search) | Check if a string contains a substring | strings.contains("hello", "ell") → true |
strings.replace(value, target, replacement) | Replace all occurrences of target with replacement | strings.replace("hello", "l", "r") → "herro" |
Usage examples:
$strings.uppercase($!request.method)strings.base64Encode(request.body)jsonTransform)Provides JSON manipulation functions for merging, sorting, and extracting data from JSON strings. Named jsonTransform to avoid collision with Velocity's built-in $json (JsonTool).
| Method | Description | Example |
|---|---|---|
jsonTransform.merge(json1, json2) | Merge two JSON objects (json2 fields overwrite json1) | jsonTransform.merge('{"a":1}', '{"b":2}') → '{"a":1,"b":2}' |
jsonTransform.sort(jsonArray, field) | Sort a JSON array of objects by a field | jsonTransform.sort('[{"n":"b"},{"n":"a"}]', "n") |
jsonTransform.arrayAdd(jsonArray, element) | Add an element to a JSON array | jsonTransform.arrayAdd('[1,2]', '3') → '[1,2,3]' |
jsonTransform.remove(json, fieldName) | Remove a field from a JSON object | jsonTransform.remove('{"a":1,"b":2}', "a") → '{"b":2}' |
jsonTransform.prettyPrint(json) | Pretty-print a JSON string | jsonTransform.prettyPrint('{"a":1}') |
jsonTransform.field(json, fieldName) | Extract a single field value from a JSON object | jsonTransform.field('{"name":"test"}', "name") → "test" |
jsonTransform.size(jsonArray) | Return the number of elements in a JSON array | jsonTransform.size('[1,2,3]') → 3 |
Usage examples:
$jsonTransform.field($!request.body, "username")jsonTransform.merge(request.body, '{"status":"processed"}')dates)Provides date/time arithmetic and formatting functions. All times are UTC-based.
| Method | Description | Example Output |
|---|---|---|
dates.format(pattern) | Format current time with a pattern (e.g., yyyy-MM-dd) | "2026-05-11" |
dates.plusSeconds(n) | Current time plus n seconds (ISO-8601) | "2026-05-11T10:15:30Z" |
dates.plusMinutes(n) | Current time plus n minutes (ISO-8601) | "2026-05-11T10:20:00Z" |
dates.plusHours(n) | Current time plus n hours (ISO-8601) | "2026-05-11T11:15:00Z" |
dates.plusDays(n) | Current time plus n days (ISO-8601) | "2026-05-12T10:15:00Z" |
dates.minusSeconds(n) | Current time minus n seconds (ISO-8601) | |
dates.minusMinutes(n) | Current time minus n minutes (ISO-8601) | |
dates.minusHours(n) | Current time minus n hours (ISO-8601) | |
dates.minusDays(n) | Current time minus n days (ISO-8601) | |
dates.epochSeconds() | Current time as Unix epoch seconds | 1747048530 |
dates.epochMillis() | Current time as Unix epoch milliseconds | 1747048530000 |
dates.epochSecondsPlus(n) | Epoch seconds plus n seconds | "1747048590" |
dates.epochSecondsMinus(n) | Epoch seconds minus n seconds | "1747048470" |
Usage examples:
$dates.plusHours(1) (token expiry 1 hour from now)dates.format("yyyy-MM-dd"){{ dates }} (outputs current ISO-8601 timestamp via toString)calc)Provides mathematical functions for generating random numbers, rounding, and formatting. Named calc to avoid collision with Velocity's built-in $math (MathTool).
| Method | Description | Example |
|---|---|---|
calc.randomInt(min, max) | Random integer between min and max (inclusive) | calc.randomInt(1, 100) → 42 |
calc.randomDouble() | Random double between 0.0 and 1.0 | 0.7312... |
calc.randomDouble(min, max) | Random double between min and max | calc.randomDouble(1.0, 5.0) |
calc.abs(value) | Absolute value | calc.abs(-5) → 5 |
calc.min(a, b) | Minimum of two integers | calc.min(3, 7) → 3 |
calc.max(a, b) | Maximum of two integers | calc.max(3, 7) → 7 |
calc.round(value, scale) | Round to specified decimal places | calc.round(3.14159, 2) → 3.14 |
calc.format(value, pattern) | Format a number with a DecimalFormat pattern | calc.format(1234.5, "#,##0.00") → "1,234.50" |
calc.ceil(value) | Round up to nearest integer | calc.ceil(3.1) → 4.0 |
calc.floor(value) | Round down to nearest integer | calc.floor(3.9) → 3.0 |
Usage examples:
$calc.randomInt(1, 1000)calc.round(calc.randomDouble(0.0, 100.0), 2)faker)Generates realistic fake data for names, addresses, emails, phone numbers, and 250+ other categories using DataFaker. A single shared Faker instance is exposed as faker in all template engines. The instance is thread-safe and produces random values on each invocation.
| Expression | Description | Example Output |
|---|---|---|
faker.name().firstName() | Random first name | "Emory" |
faker.name().lastName() | Random last name | "Johnson" |
faker.name().fullName() | Random full name | "Dr. Jane Smith" |
faker.internet().emailAddress() | Random email address | "john.doe@example.com" |
faker.internet().url() | Random URL | "https://www.example.com" |
faker.address().city() | Random city name | "Brittneymouth" |
faker.address().streetAddress() | Random street address | "123 Main St" |
faker.address().zipCode() | Random ZIP/postal code | "90210" |
faker.phoneNumber().cellPhone() | Random phone number | "(555) 123-4567" |
faker.lorem().sentence() | Random sentence of text | "Lorem ipsum dolor sit amet." |
faker.number().numberBetween(1, 100) | Random integer in range | 42 |
faker.company().name() | Random company name | "Acme Corp" |
Usage examples:
$faker.name().firstName() or $faker.internet().emailAddress(){{ faker.name.firstName }} or {{ faker.internet.emailAddress }}faker.name().firstName() or faker.internet().emailAddress()The full list of available providers (name, address, internet, company, finance, medical, etc.) is documented in the DataFaker providers reference.
crypto)Computes cryptographic digests and HMAC signatures. All methods return lowercase hex strings. Use this to generate request signatures, verify webhook payloads, or add content-hashing headers in templated responses.
| Method | Description | Example |
|---|---|---|
crypto.md5(s) | MD5 digest of a string | crypto.md5("hello") → "5d41402abc4b2a76b9719d911017c592" |
crypto.sha1(s) | SHA-1 digest | crypto.sha1("hello") → "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d" |
crypto.sha256(s) | SHA-256 digest | crypto.sha256("hello") → "2cf24dba5fb0a30e26e83b2ac5b9e29e..." |
crypto.sha512(s) | SHA-512 digest | crypto.sha512("hello") → "9b71d224bd62f3785d96d46ad3ea3d..." |
crypto.hmacSha256(key, data) | HMAC-SHA-256 of data using key | crypto.hmacSha256("secret", "payload") → lowercase hex |
Usage examples:
$crypto.sha256($!request.body) (hash the request body into a response field){{ crypto.sha256 }} is not directly callable with arguments in Mustache — use Velocity or JavaScript when you need to pass a value to a crypto methodcrypto.hmacSha256("my-secret", request.body)regex)Applies Java regular expressions to strings inside a template. Use this to extract captured groups from request data or rewrite parts of a value before including it in the response.
| Method | Description | Example |
|---|---|---|
regex.matches(input, pattern) | Returns true if the pattern matches anywhere in the input | regex.matches("hello world", "\\bworld\\b") → true |
regex.replaceAll(input, pattern, replacement) | Replaces all matches of the pattern with the replacement string; supports $1 back-references | regex.replaceAll("foo123bar", "[0-9]+", "NUM") → "fooNUMbar" |
regex.group(input, pattern, groupIndex) | Returns the captured group at groupIndex (1-based) from the first match, or "" if there is no match | regex.group("user-42", "user-([0-9]+)", 1) → "42" |
Usage examples:
$regex.group($!request.path, "/orders/([^/]+)", 1) (extract the order ID from the path)regex.replaceAll(request.headers["Authorization"][0], "^Bearer ", "") (strip the Bearer prefix from a token)html)Escapes and unescapes HTML entities (HTML 4.0). Use this to safely embed request data in an HTML response body, or to recover the original text from an escaped value.
| Method | Description | Example |
|---|---|---|
html.escape(value) | Escapes characters using HTML entities | html.escape("<a> & <b>") → "<a> & <b>" |
html.unescape(value) | Reverses HTML entity escaping | html.unescape("<a>") → "<a>" |
Usage examples:
$html.escape($!request.body) (safely embed the request body in HTML)html.unescape(request.queryStringParameters["q"][0])csv)Parses CSV text into rows (each row a list of fields) and formats a list of fields back into a CSV line. Quoting and quote-doubling follow RFC 4180: fields containing a comma, double-quote, or newline are wrapped in double quotes and embedded quotes are doubled.
| Method | Description | Example |
|---|---|---|
csv.parse(text) | Parses CSV text into a list of rows, each a list of fields | csv.parse("a,b\n1,2") → [["a","b"],["1","2"]] |
csv.row(list) | Formats a list of fields into a single CSV line, quoting where required | csv.row(["a","b,c"]) → "a,\"b,c\"" |
Usage examples:
csv.parse(request.body)[0][1] (read the second field of the first CSV row)csv.row(["id","name","total"]) (build a CSV header line for a response)xpath)Evaluates an XPath expression against an XML document and returns the string result. The XML parser disables DOCTYPE declarations and external entity resolution, so it is safe against XXE; an unparseable document or invalid expression yields "".
| Method | Description | Example |
|---|---|---|
xpath.evaluate(xml, expression) | Returns the string result of the XPath expression against the XML | xpath.evaluate("<o><id>42</id></o>", "/o/id") → "42" |
Usage examples:
$xpath.evaluate($!request.body, "/order/id") (extract an element from an XML request body)xpath.evaluate(request.body, "/order/@status") (read an attribute value)yaml)Converts a YAML document to JSON and reads a top-level field out of a YAML document. Scalar fields are returned verbatim; object/array fields are returned as JSON.
| Method | Description | Example |
|---|---|---|
yaml.toJson(yaml) | Converts a YAML document to its JSON representation | yaml.toJson("name: Bob") → "{\"name\":\"Bob\"}" |
yaml.parse(yaml, field) | Returns a top-level field value (scalars verbatim, objects/arrays as JSON) | yaml.parse("name: Bob", "name") → "Bob" |
Usage examples:
$yaml.toJson($!request.body) (turn a YAML request body into a JSON response)yaml.parse(request.body, "version")The following shows a basic example for a mustache format response template
new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
HttpTemplate.TemplateType.MUSTACHE,
"{\n" +
" 'statusCode': 200,\n" +
" 'cookies': {\n" +
" 'session': '{{ request.headers.Session-Id.0 }}'\n" +
" },\n" +
" 'headers': {\n" +
" 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ]\n" +
" },\n" +
" 'body': '{{ request.body }}'\n" +
"}"
)
);
var mockServerClient = require('mockserver-client').mockServerClient;
mockServerClient("localhost", 1080).mockAnyResponse({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}).then(
function () {
console.log("expectation created");
},
function (error) {
console.log(error);
}
);
See REST API for full JSON specification
from mockserver.client import MockServerClient
from mockserver.models import Expectation
client = MockServerClient("localhost", 1080)
client.upsert(Expectation.from_dict({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}))
require 'mockserver-client'
client = MockServer::Client.new('localhost', 1080)
client.upsert(MockServer::Expectation.from_hash({
'httpRequest' => {
'path' => '/some/path'
},
'httpResponseTemplate' => {
'template' => "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
'templateType' => 'MUSTACHE'
}
}))
package main
import (
"bytes"
"net/http"
)
func main() {
body := []byte(`{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}`)
req, _ := http.NewRequest("PUT",
"http://localhost:1080/mockserver/expectation",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
using System.Net.Http;
using System.Text;
using var httpClient = new HttpClient();
var json = @"{
""httpRequest"": {
""path"": ""/some/path""
},
""httpResponseTemplate"": {
""template"": ""{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }"",
""templateType"": ""MUSTACHE""
}
}";
await httpClient.PutAsync(
"http://localhost:1080/mockserver/expectation",
new StringContent(json, Encoding.UTF8, "application/json")
);
use reqwest::blocking::Client;
let client = Client::new();
let body = r#"{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}"#;
client.put("http://localhost:1080/mockserver/expectation")
.header("Content-Type", "application/json")
.body(body.to_string())
.send()
.unwrap();
$json = <<<'JSON'
{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}
JSON;
$ch = curl_init('http://localhost:1080/mockserver/expectation');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json; charset=utf-8'],
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
curl_close($ch);
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '{{ request.headers.Session-Id.0 }}' }, 'headers': { 'Client-User-Agent': [ '{{ request.headers.User-Agent.0 }}' ] }, 'body': '{{ request.body }}' }",
"templateType": "MUSTACHE"
}
}'
See REST API for full JSON specification
In mustache a variable is referenced using double braces, for example, {{ request.method }} will print the method field of the request
variable.
{{ name }} will try to find the name key in the current model context; which can be changed, using sections, as described below.
If no matching field is found an empty string will be returned.
The following basic template example demonstrates using multiple variables:
{
'statusCode': 200,
'body': {
'method': '{{ request.method }}',
'path': '{{ request.path }}',
'headers': '{{ request.headers.host.0 }}'
}
}
Sections have the following uses:
A section begins with a tag starting with a pound and ends with a matching tag starting with a slash.
For example {{#request.cookies}} starts a request.cookies section and {{/request.cookies}} closes the section.
How a section behaves depends on the section's model variable as follows
The following example template demonstrates using a section to iterate the entrySet in the header map:
{
'statusCode': 200,
'body': "{'headers': '{{#request.headers.entrySet}}{{ key }}={{ value.0 }} {{/request.headers.entrySet}}'}"
}
And produces the following example output:
{
"statusCode" : 200,
"body" : "{'headers': 'host=mock-server.com content-type=plain/text '}"
}
An inverted section begins with a tag starting with a caret and ends with a matching tag starting with a slash.
For example {{^-first}} starts a -first section and {{/-first}} closes the section. This section therefore applies for all items in a list except the first item.
Inverted sections render once based on the inverse value of the key, they will be rendered if the key doesn't exist, is false, is an empty string, or is an empty list.
The following example template demonstrates using a section to iterate the entrySet in the header map using an inverted section and the special variable -first to add commas before all headers except the first:
{
'statusCode': 200,
'body': "{'headers': [{{#request.headers.entrySet}}{{^-first}}, {{/-first}}'{{ key }}={{ value.0 }}'{{/request.headers.entrySet}}]}"
}
And produces the following example output:
{
"statusCode" : 200,
"body" : "{'headers': ['host=mock-server.com', 'content-type=plain/text']}"
}
this refers to the context object itself such as the current item when iterating over a collection
You can use the special variables -first and -last when using collections.
-first resolves to true when inside a section on the first iteration, it resolves to false at all other times. It resolves to false for sections with a singleton value rather a collection.
-last resolves to true when inside a section on the last iteration, it resolves to false at all other times.
The -index special variable resolves to 1 for the first iteration, 2 for the second so on. It resolves to 0 at all other times including sections with a singleton value rather a collection.
The following example template demonstrates using this and -first to list header values
{
'statusCode': 200,
'body': "{'headers': [{{#request.headers.values}}{{^-first}}, {{/-first}}'{{ this.0 }}'{{/request.headers.values}}]}"
}
And produces the following example output:
{
"statusCode" : 200,
"body" : "{'headers': ['mock-server.com', 'plain/text']}"
}
The following example template demonstrates using this, -first and -index to list header keys
{
'statusCode': 200,
'body': "{'headers': [{{#request.headers.keySet}}{{^-first}}, {{/-first}}'{{ -index }}:{{ this }}'{{/request.headers.keySet}}]}"
}
And produces the following example output:
{
"statusCode" : 200,
"body" : "{'headers': ['1:host', '2:content-type']}"
}
It is possible to use JsonPath expressions to extract values from request bodies containing JSON with a {{#jsonPath}} section, follow by a {{#jsonPathResult}} section
For details of the full JsonPath syntax please see github.com/json-path
The following example template demonstrates using {{#jsonPath}} follow by {{#jsonPathResult}} to extract a list and single value from a request body:
{
'statusCode': 200,
'body': "{'titles': {{#jsonPath}}$.store.book{{/jsonPath}}[{{#jsonPathResult}}{{^-first}}, {{/-first}}'{{title}}'{{/jsonPathResult}}], 'bikeColor': '{{#jsonPath}}$.store.bicycle.color{{/jsonPath}}{{jsonPathResult}}'}"
}
In this example the first JsonPath expression $.store.book returns a list of objects which is iterated over in the section {{#jsonPathResult}}.
The second JsonPath expression $.store.bicycle.color returns a single value which is returned using the variable tag {{jsonPathResult}}.
Given the following request:
{
"path" : "/somePath",
"body" : {
"store" : {
"book" : [ {
"category" : "reference",
"author" : "Nigel Rees",
"title" : "Sayings of the Century",
"price" : 18.95
}, {
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
} ],
"bicycle" : {
"color" : "red",
"price" : 19.95
}
},
"expensive" : 10
}
}
The example produces:
{
"statusCode" : 200,
"body" : "{'titles': ['Sayings of the Century', 'Moby Dick'], 'bikeColor': 'red'}"
}
It is possible to use XPath expressions to extract values from request bodies containing XML with a {{#xPath}} section.
The {{#xPath}} section only supports outputting the result of the XPath expression as a string, if an XML fragment is matched the string content of all the elements is printed.
For a quick summary the XPath syntax please see w3schools, for details of the full XPath syntax please see www.w3.org
The following example template demonstrates using {{#xPath}} to multiple items from a request body:
{
'statusCode': 200,
'body': "{'titles': ['{{#xPath}}/store/book/title{{/xPath}}', '{{#xPath}}//book[2]/title{{/xPath}}'], 'bikeColor': '{{#xPath}}//bicycle/color{{/xPath}}'}"
}
Given a request with the following xml body:
<?xml version="1.0" encoding="UTF-8" ?>
<store>
<book>
<category>reference</category>
<author>Nigel Rees</author>
<title>Sayings of the Century</title>
<price>18.95</price>
</book>
<book>
<category>fiction</category>
<author>Herman Melville</author>
<title>Moby Dick</title>
<isbn>0-553-21311-3</isbn>
<price>8.99</price>
</book>
<bicycle>
<color>red</color>
<price>19.95</price>
</bicycle>
<expensive>10</expensive>
</store>
The example produces:
{
"statusCode" : 200,
"body" : "{'titles': ['Sayings of the Century', 'Moby Dick'], 'bikeColor': 'red'}"
}
The following shows a basic example for a Velocity format response template
new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
HttpTemplate.TemplateType.VELOCITY,
"{\n" +
" 'statusCode': 200,\n" +
" 'cookies': { \n" +
" 'session': '$!request.headers['Session-Id'][0]'\n" +
" },\n" +
" 'headers': {\n" +
" 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ]\n" +
" },\n" +
" 'body': '$!request.body'\n" +
"}"
)
);
var mockServerClient = require('mockserver-client').mockServerClient;
mockServerClient("localhost", 1080).mockAnyResponse({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}).then(
function () {
console.log("expectation created");
},
function (error) {
console.log(error);
}
);
See REST API for full JSON specification
from mockserver.client import MockServerClient
from mockserver.models import Expectation
client = MockServerClient("localhost", 1080)
client.upsert(Expectation.from_dict({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}))
require 'mockserver-client'
client = MockServer::Client.new('localhost', 1080)
client.upsert(MockServer::Expectation.from_hash({
'httpRequest' => {
'path' => '/some/path'
},
'httpResponseTemplate' => {
'template' => "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
'templateType' => 'VELOCITY'
}
}))
package main
import (
"bytes"
"net/http"
)
func main() {
body := []byte(`{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}`)
req, _ := http.NewRequest("PUT",
"http://localhost:1080/mockserver/expectation",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
using System.Net.Http;
using System.Text;
using var httpClient = new HttpClient();
var json = @"{
""httpRequest"": {
""path"": ""/some/path""
},
""httpResponseTemplate"": {
""template"": ""{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }"",
""templateType"": ""VELOCITY""
}
}";
await httpClient.PutAsync(
"http://localhost:1080/mockserver/expectation",
new StringContent(json, Encoding.UTF8, "application/json")
);
use reqwest::blocking::Client;
let client = Client::new();
let body = r#"{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}"#;
client.put("http://localhost:1080/mockserver/expectation")
.header("Content-Type", "application/json")
.body(body.to_string())
.send()
.unwrap();
$json = <<<'JSON'
{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}
JSON;
$ch = curl_init('http://localhost:1080/mockserver/expectation');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json; charset=utf-8'],
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
curl_close($ch);
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "{ 'statusCode': 200, 'cookies': { 'session': '$!request.headers['Session-Id'][0]' }, 'headers': { 'Client-User-Agent': [ '$!request.headers['User-Agent'][0]' ] }, 'body': '$!request.body' }",
"templateType": "VELOCITY"
}
}'
See REST API for full JSON specification
For full Velocity syntax see: Velocity User Guide the following section provide a basic summary and examples of Velocity syntax.
In velocity a variable is referenced using a dollar, for example, $request.method will print the method field of the request variable.
$name will try to find the name variable in the current model.
If no matching variable is found for the variable expression the expression is printed, unless a quiet expression notation is used as follows $!name
The following basic template example demonstrates using multiple variables:
{
'statusCode': 200,
'body': {
'method': '$!request.method',
'path': '$!request.path',
'headers': '$!request.headers.host.0'
}
}
Methods can also be called on variables, for example, $request.getMethod() will call the getMethod() method of the request variable.
New variables can be defined using a #set directive, for example, #set ($message="Hello World") will create a new variables call message.
Conditional expressions are possible using #if, #elseif and #else directives, as follows:
#if($request.method == 'POST' && $request.path == '/somePath')
{
'statusCode': 200,
'body': "{'name': 'value'}"
}
#else
{
'statusCode': 406,
'body': "$!request.body"
}
#end
Loops are possible using the #foreach directives, as follows:
{
'statusCode': 200,
'body': "{'headers': [#foreach( $value in $request.headers.values() )'$value[0]'#if( $foreach.hasNext ), #end#end]}"
}
The example produces:
{
"statusCode" : 200,
"body" : "{'headers': ['mock-server.com', 'plain/text']}"
}
In addition to the dynamic model variables it is possible to perform basic mathematical operations, as follows:
#set($percent = $number / 100)
#set($remainder = $dividend % $divisor)
A range operator is also supported which can be useful in conjunction with #set and #foreach
#set($array = [0..10])
#foreach($item in $arr)
$item
#end
For additional mathematical functionality it is also possible to use the MathTool or NumberTool in velocity response templates.
#set($power = $math.pow($number, 2))
#set($max = $math.max($number, 10))
The JsonTool can be used to help parse JSON bodies, as follows:
#set($jsonBody = $json.parse($!request.body))
{
'statusCode': 200,
'body': "{'titles': [#foreach( $book in $jsonBody.store.book )'$book.title'#if( $foreach.hasNext ), #end#end], 'bikeColor': '$jsonBody.store.bicycle.color'}"
}
Given the following request:
{
"path" : "/somePath",
"body" : {
"type" : "JSON",
"json" : {
"store" : {
"book" : [ {
"category" : "reference",
"author" : "Nigel Rees",
"title" : "Sayings of the Century",
"price" : 18.95
}, {
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
} ],
"bicycle" : {
"color" : "red",
"price" : 19.95
}
},
"expensive" : 10
}
}
}
The example produces:
{
"statusCode" : 200,
"body" : "{'titles': ['Sayings of the Century', 'Moby Dick'], 'bikeColor': 'red'}"
}
The XmlTool can be used to help parse XML bodies, execute XPath and XML traversal.
The following example shows how to use XmlTool for XPath:
#set($xmlBody = $xml.parse($!request.body))
{
'statusCode': 200,
'body': "{'key': '$xml.find('/element/key/text()')', 'value': '$xml.find('/element/value/text()')'}"
}
Given the following request:
{
"path" : "/somePath",
"body" : "<element><key>some_key</key><value>some_value</value></element>"
}
The example produces:
{
"statusCode" : 200,
"body" : "{'key': 'some_key', 'value': 'some_value'}"
}
As a quicker alternative to $xml.parse() / $json.parse(), Velocity templates can extract a single value directly from the request body using the same JsonPath and XPath support as Mustache templates, via the $jsonPath and $xPath helpers:
{
'statusCode': 200,
'body': "{'title': '$jsonPath.find('$.store.book[0].title')', 'key': '$xPath.find('/element/key')'}"
}
$jsonPath.find(...) evaluates a JsonPath expression against a JSON request body and $xPath.find(...) evaluates an XPath expression against an XML request body. A missing path or invalid expression resolves to an empty value (the error is logged, not thrown), exactly as in Mustache templates.
The following velocity tools are available for velocity response templates:
The following shows a basic example for a JavaScript format response template
new ClientAndServer(1080)
.when(request().withPath("/some/path"))
.respond(
template(
HttpTemplate.TemplateType.JAVASCRIPT,
"return {\n" +
" 'statusCode': 200,\n" +
" 'cookies': {\n" +
" 'session' : request.headers['session-id'][0]\n" +
" },\n" +
" 'headers': {\n" +
" 'Client-User-Agent': request.headers['User-Agent']\n" +
" },\n" +
" 'body': request.body\n" +
"};"
)
);
var mockServerClient = require('mockserver-client').mockServerClient;
mockServerClient("localhost", 1080).mockAnyResponse({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}).then(
function () {
console.log("expectation created");
},
function (error) {
console.log(error);
}
);
See REST API for full JSON specification
from mockserver.client import MockServerClient
from mockserver.models import Expectation
client = MockServerClient("localhost", 1080)
client.upsert(Expectation.from_dict({
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}))
require 'mockserver-client'
client = MockServer::Client.new('localhost', 1080)
client.upsert(MockServer::Expectation.from_hash({
'httpRequest' => {
'path' => '/some/path'
},
'httpResponseTemplate' => {
'template' => "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
'templateType' => 'JAVASCRIPT'
}
}))
package main
import (
"bytes"
"net/http"
)
func main() {
body := []byte(`{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}`)
req, _ := http.NewRequest("PUT",
"http://localhost:1080/mockserver/expectation",
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
using System.Net.Http;
using System.Text;
using var httpClient = new HttpClient();
var json = @"{
""httpRequest"": {
""path"": ""/some/path""
},
""httpResponseTemplate"": {
""template"": ""return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };"",
""templateType"": ""JAVASCRIPT""
}
}";
await httpClient.PutAsync(
"http://localhost:1080/mockserver/expectation",
new StringContent(json, Encoding.UTF8, "application/json")
);
use reqwest::blocking::Client;
let client = Client::new();
let body = r#"{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}"#;
client.put("http://localhost:1080/mockserver/expectation")
.header("Content-Type", "application/json")
.body(body.to_string())
.send()
.unwrap();
$json = <<<'JSON'
{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}
JSON;
$ch = curl_init('http://localhost:1080/mockserver/expectation');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json; charset=utf-8'],
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
curl_close($ch);
curl -v -X PUT "http://localhost:1080/mockserver/expectation" -d '{
"httpRequest": {
"path": "/some/path"
},
"httpResponseTemplate": {
"template": "return { 'statusCode': 200, 'cookies': { 'session' : request.headers['session-id'][0] }, 'headers': { 'Client-User-Agent': request.headers['User-Agent'] }, 'body': request.body };",
"templateType": "JAVASCRIPT"
}
}'
See REST API for full JSON specification
All javascript response templates should return the response as an object as shown in the example above.
MockServer uses the GraalVM Polyglot JavaScript engine for JavaScript templates. The engine is not bundled with the standard Docker image or the standalone JAR — only the text-based Mustache and Velocity engines are available by default. To use JavaScript templates, either run the graaljs Docker image variant (e.g. mockserver/mockserver:{{ site.mockserver_version }}-graaljs) or add org.graalvm.polyglot:polyglot and org.graalvm.polyglot:js to your classpath (see below). It supports ES2023+ syntax, including template literals, async/await, destructuring, optional chaining, and the full modern JavaScript language.
If a JAVASCRIPT template is used when the GraalJS engine is not on the classpath, the request now fails with a clear error rather than silently returning a degraded/empty response: "JavaScript response templates require the GraalJS engine, which is not on the classpath. Add the org.graalvm.polyglot:js (or js-community) dependency, or use the Velocity or Mustache template engine." Add the GraalJS dependency (or switch to Velocity/Mustache) to resolve it.
If you are embedding MockServer as a library and need JavaScript templating, add org.graalvm.polyglot:polyglot and org.graalvm.polyglot:js (both at version 25.0.3 or later) to your classpath. Nashorn (org.openjdk.nashorn:nashorn-core) is no longer supported; the JSR-223 bridge was dropped in GraalJS 25.x and Nashorn was removed from MockServer.
In javascript a variable is referenced directly, for example, request.method will return the method field of the request variable.
The following basic template example demonstrates using multiple variables:
return {
'statusCode': 200,
'body': '{\'method\': \'' + request.method + '\', \'path\': \'' + request.path + '\', \'header\': \'' + request.headers.host[0] + '\'}'
};
As an alternative to JSON.parse(request.body), JavaScript templates can extract a single value directly from the request body using the same JsonPath and XPath support as Mustache templates, via the jsonPath(...) and xPath(...) functions:
return {
'statusCode': 200,
'body': '{\'title\': \'' + jsonPath('$.store.book[0].title') + '\', \'key\': \'' + xPath('/element/key') + '\'}'
};
jsonPath(...) evaluates a JsonPath expression against a JSON request body and xPath(...) evaluates an XPath expression against an XML request body. A missing path or invalid expression returns an empty value (the error is logged, not thrown), exactly as in Mustache templates.
Conditional expressions are possible, as follows:
if (request.method === 'POST' && request.path === '/somePath') {
return {
'statusCode': 200,
'body': JSON.stringify({name: 'value'})
};
} else {
return {
'statusCode': 406,
'body': request.body
};
}
Looping is possible, as follows:
var headers = '';
for (header in request.headers) {
headers += '\'' + request.headers[header] + '\', ';
}
return {
'statusCode': 200,
'body': '{\'headers\': [' + headers.slice(0, -2) + ']}'
};
The example produces:
{
"statusCode" : 200,
"body" : "{'headers': ['mock-server.com', 'plain/text']}"
}
Response templates execute code. A template that can reach classes such as java.lang.Runtime or java.lang.ProcessBuilder can run OS commands inside the MockServer process, so anyone able to register an expectation could run code on the machine MockServer is running on.
Templates cannot reach Java classes out of the box, so this is safe by default and you do not need to configure anything:
velocityDisallowClassLoading now defaults to true, so class loading from within a Velocity template (for example $request.class.classLoader.loadClass(...)) is blocked.javascriptAllowedClasses. Java.type(...) and the java.* globals return nothing until then; the rest of the language is unaffected.Everything templates are normally used for still works: request values, the built-in helpers ($uuid, $now, $faker, JWT, string, date and math helpers), the $json/$xml tools, and the whole modern JavaScript standard library.
If a template of yours genuinely needs a Java class, grant the minimum it needs:
-Dmockserver.javascriptAllowedClasses="java.util.*,java.time.Instant". Use * to let templates resolve any class again, and only when every template comes from a source you fully trust.-Dmockserver.velocityDisallowClassLoading=false re-enables class loading for all Velocity templates, with the same caveat.For JavaScript templates, a refused class is written to the log at WARN naming the class and the property to set, so a template that stops working tells you exactly what to grant. A Velocity template that is refused a class simply renders that part of the output empty.
See the configuration properties page for the full list of equivalent system-property, environment-variable, and Java API forms of these settings. To stop untrusted callers from registering templated expectations in the first place, also enable control plane authorisation.