In WireMock, why does a templated body render " where a quote should be?
answer
- WireMock renders replies with Handlebars
- a web-page default landing in JSON
- quotes and ampersands become entities
- one more brace turns escaping off
- raw output means you own the quoting
basics
~20 sHandlebars escapes double-brace output for HTML, so WireMock turns a quote into the " entity. In WireMock, the triple-brace form emits the helper's output raw instead. Use it whenever a WireMock template injects JSON or XML into a reply.
solid answer
~40 sWireMock renders templates with Handlebars, and Handlebars escapes the output of a `{{ ... }}` expression for HTML: `"` becomes `"`, `&` becomes `&`, `<` becomes `<`. That is the correct default for a web page and exactly wrong for a JSON reply, so a WireMock stub that injects a value pulled with `{{jsonPath request.body '$.manifest'}}` produces a payload full of entities that no client will parse. The fix is the triple-brace form, `{{{jsonPath request.body '$.manifest'}}}`, which WireMock emits raw. The tradeoff moves rather than disappears: with the triple brace you own escaping, so a value containing a stray quote now breaks the JSON you are assembling by hand. Inject whole sub-documents with the triple brace, and keep free-text scalars somewhere you control the quoting.
code
json · 12 lines{
"request": {
"method": "POST",
"urlPath": "/dispatch/v1/assignments"
},
"response": {
"status": 201,
"headers": { "Content-Type": "application/json" },
"body": "{ \"routeId\": \"{{jsonPath request.body '$.routeId'}}\", \"manifest\": {{{jsonPath request.body '$.manifest'}}} }",
"transformers": ["response-template"]
}
}go deeper
Recognise entity text like " in a stubbed reply as an escaping symptom rather than a broken client, and know that WireMock templates are rendered by Handlebars.
Explain that the double brace escapes for HTML and the triple brace emits raw, and say which one a JSON reply wants and why the default is what it is.
Diagnose it from the wire, and reason about what the triple brace hands back: a document goes in unquoted, a scalar inside quotes, and uncontrolled free text needs the matcher narrowed instead.
Set the convention for stub authors across suites, because every failure mode here is silent and the first signal is a client that could not read a reply the stub server called a success.
## Why a quote turns into an entity WireMock's response templating is Handlebars, and Handlebars has one behaviour that surprises everybody who meets it outside a web page: a `{{ expression }}` is **HTML-escaped** on the way out. Five characters are rewritten — `"` to `"`, `'` to `'`, `&` to `&`, `<` to `<` and `>` to `>`. In a template that produces HTML this is a safety feature and the reason the default exists. In a WireMock stub answering a snowplough dispatch API with JSON, it is a corruption. The symptom is unmistakable once you have seen it. The stub answers `201` as designed, the body has the right fields in the right order, and every embedded quote is an entity: - Expected: `{"manifest": {"laneKm": 14, "saltTonnes": 3}}` - Rendered: `{"manifest": {"laneKm": 14 ...` No client will parse that, and no WireMock log will complain about it, because from the server's point of view nothing went wrong. ## Double brace versus triple brace | Form | What WireMock emits | Use it for | |---|---|---| | `{{jsonPath request.body '$.notes'}}` | the helper's output, HTML-escaped | text destined for an HTML body, where escaping is protection | | `{{{jsonPath request.body '$.notes'}}}` | the helper's output exactly as produced | JSON, XML, and any document you are assembling character by character | The triple brace is not a WireMock invention; it is the Handlebars escape hatch, and WireMock inherits it along with the escaping default. Nothing else about the expression changes — same helper, same arguments, same source — only whether the result is rewritten before it lands in the reply. ## What the triple brace hands back to you Switching a WireMock template to `{{{ }}}` does not remove the escaping problem, it transfers ownership of it: - A value that contains a `"` will now terminate the JSON string you placed it in, producing a body that is malformed in a new way. - A value that contains a newline will do the same, because a raw newline is not legal inside a JSON string. - A value taken straight from the request is attacker-controlled in exactly the sense a real service would care about, and the stub is now concatenating it into a document. The practical division that follows: 1. **Whole sub-documents** — a manifest, a nested object, an array pulled out of the request — belong in a triple brace, unquoted, because the helper's output is already valid JSON and quoting it would be wrong twice over. 2. **Scalars you control** — a route id, a depot code, an enum value — are safe in a triple brace inside quotes, because you know their shape. 3. **Free text of unknown shape** — an operator's note, a caller-supplied description — is the case with no clean answer. Either keep it out of the templated reply, or accept that a stub is not the place to do robust escaping and pin the fixture to a value you chose. ## Where this bites on a dispatch API The classic version is a confirmation reply that echoes the submitted manifest back. The WireMock stub author writes `"manifest": "{{jsonPath request.body '$.manifest'}}"` — quoted, double brace — and gets two defects at once: the sub-document has been flattened into a string, and every quote inside it has become an entity. In WireMock the correct shape is `"manifest": {{{jsonPath request.body '$.manifest'}}}` with no surrounding quotes at all, because the helper already yields a JSON object. The second version is subtler. A field renders fine in every test until a caller submits a route note containing an apostrophe, and one test in a nightly run starts failing on a body it cannot parse. The template did nothing different; the data did. ## Deciding which form to write 1. Ask what the rendered value is going into. HTML wants the double brace; JSON and XML almost always want the triple. 2. Ask whether the value is a document or a scalar. A document goes in unquoted with a triple brace; a scalar goes inside quotes. 3. Ask who controls the value's characters. If the answer is "the caller", either narrow the stub's matcher so only known-shaped payloads reach it, or stop echoing that field. 4. Read the rendered reply once against a realistic request, not a minimal one. A body of clean identifiers hides this defect completely. The reason this belongs to production judgment rather than to trivia is that every failure mode here is silent. WireMock's escaping default is applied without comment, the triple brace's hazards are applied without comment, and the only signal in either direction is a client that could not read a reply the stub server considered a success.
- When is the double-brace form still the right choice in a WireMock template?Whenever the rendered value is going into markup. If a WireMock stub serves an HTML fragment for a browser test, the escaping default is protection: a value carrying `<` or `&` is neutralised before it reaches the page. Reaching for the triple brace there removes a safeguard for no benefit.
- Why is a stub that echoes caller-supplied free text with a triple brace fragile?Because the stub is concatenating an uncontrolled value into a document it is assembling by hand, and a single quote or newline in that value makes the reply unparseable. The template is unchanged; only the data changed. Either narrow the WireMock matcher so only known-shaped payloads reach the stub, or stop echoing that field.
saying these in an interview costs you the question
- Blames the client's parser for a body full of " entities
- Wraps a triple-brace sub-document in quotes as well
- Thinks the triple brace escapes for JSON instead of disabling escaping
- Assumes WireMock warns when a rendered body stops being valid JSON
- Uses the triple brace on caller-supplied free text without narrowing the matcher