In WireMock, why does a stubbed body containing `{{request.path}}` come back unrendered?
answer
- rendering is opt-in, not automatic
- the body was served, not interpreted
- something must name the transformer
- WireMock resolves response-template exactly
- WireMock withTransformers, or the global flag
basics
~20 sWireMock renders a stub body only when the response-template transformer is attached to that response. Without it, WireMock treats the body as literal bytes and returns the Handlebars source unchanged. Attach it with withTransformers, or launch WireMock with --global-response-templating.
solid answer
~40 sResponse templating in WireMock is opt-in per response, not a global default. A WireMock response definition renders Handlebars only when the `response-template` transformer is attached to it, so a body written as a template but served without that attachment goes out byte for byte and the caller receives the literal characters `{{request.path}}`. Attach it in WireMock's Java DSL with `aResponse().withBody(...).withTransformers("response-template")`, or in a WireMock JSON stub mapping with `"transformers": ["response-template"]` inside the `response` object rather than beside it. WireMock never warns you about this: it does not scan bodies for braces, so an unrendered template is a perfectly valid 201 carrying a payload the client cannot use. If a whole standalone instance is dynamic, start WireMock with `--global-response-templating`; `--local-response-templating` is WireMock's explicit name for the opt-in default you already have.
go deeper
Be ready to say that WireMock templating is opt-in and to name the string response-template. Knowing that a missing transformer produces a literal body rather than an error is the whole first-screen answer.
Explain the mechanics: where the transformer name goes in the Java DSL and in a JSON mapping, that rendering happens after matching, and that WireMock gives no warning when a template is served unrendered.
Show how you would diagnose it on a running instance — read the mapping back, check the exact spelling, then check how the server was launched — and say why silence rather than an error is the dangerous part.
Own the instance-wide choice: whether a shared WireMock renders every response by default or opts in per stub, and what that decision costs a team whose fixture bodies legitimately contain braces.
## What response templating is A WireMock stub mapping has two halves: a request pattern that decides which calls it answers, and a response definition that says what comes back. By default that response definition is inert — the bytes you handed to WireMock's `aResponse().withBody(...)` are the bytes written to the socket. That is the right default. Most stubs want a fixed payload, and a server that tried to interpret every body would mangle the ones that legitimately contain braces. Response templating is the opt-in that changes it. When a WireMock response is templated, the server passes the body and the header values through **Handlebars** before sending them, so a body written as `{"acceptedPath": "{{request.path}}"}` leaves the server as `{"acceptedPath": "/dispatch/v1/assignments"}`. The component that performs this in WireMock is `ResponseTemplateTransformer`, and the name a mapping refers to it by is the exact string **`response-template`**. ## Why a template comes back as text There is one cause worth checking before any other: the transformer is not attached to that response. WireMock does not sniff bodies for `{{`, it does not log a warning when a body looks like an unrendered template, and it does not fail the request. WireMock answers with the status you asked for and a payload containing the literal characters `{{request.path}}`. Downstream that surfaces as a deserialisation failure or, worse, as those braces being stored as a snowplough route identifier. The attachment goes missing in four recognisable ways: - The WireMock Java DSL chain stops one call early: `aResponse().withBody(...)` with no `.withTransformers("response-template")` after it. - A WireMock JSON stub mapping carries `"transformers": ["response-template"]` at the top level of the mapping instead of inside its `response` object, which is where the server looks. - The name is spelled `responseTemplate`, `response_template` or `ResponseTemplateTransformer`, none of which WireMock resolves, because it matches the transformer by that one exact string and renders nothing otherwise. - The mapping is fine, but it was written for a WireMock instance launched with `--global-response-templating` and is being served by one running the opt-in default. ## Attaching it, in both dialects In WireMock's Java DSL the switch is one call on the response builder: ```java stubFor(post(urlPathEqualTo("/dispatch/v1/assignments")) .willReturn(aResponse() .withStatus(201) .withBody("{{request.path}} accepted") .withTransformers("response-template"))); ``` In a WireMock JSON mapping it is an array inside the response object: ```json { "request": { "method": "POST", "urlPath": "/dispatch/v1/assignments" }, "response": { "status": 201, "body": "{{request.path}} accepted", "transformers": ["response-template"] } } ``` Both forms say the same thing to the same component, and neither of them changes matching. Templating decides what the reply contains; it never decides which stub answers. ## Per stub, or for the whole server Two WireMock standalone flags set the default for an instance: 1. `--global-response-templating` makes every response that WireMock instance serves render. It suits an instance whose entire mapping set is dynamic, and it removes the per-mapping noise of repeating the transformer name in every file. 2. `--local-response-templating` states WireMock's opt-in default out loud: a response renders only if it asked to. It is the safer setting for a mixed set, because a fixture body that legitimately contains `{{` — a page fragment, a configuration document, some other tool's template — is then served untouched. Deciding this once per instance is cheaper than rediscovering it per stub, and the choice belongs in whatever starts the server, not in the mappings. ## The same idea, three different shapes | Server | How a reply becomes dynamic | What people get wrong | |---|---|---| | WireMock | attach the `response-template` transformer to the response, or launch with `--global-response-templating` | the transformer is simply not attached, so the Handlebars source ships as data | | MockServer | build the reply as a template with `HttpTemplate.template(TemplateType.VELOCITY, ...)` instead of a literal `response()` | there is nothing to attach — a template and a literal reply are different kinds of response | | Mountebank | add `decorate`, `copy` or `lookup` to that response's `behaviors` array | quoting `repeat` as a behavior, when it is a field on the response and not one of the five behaviors | The first row is the one this question turns on. WireMock is the server of the three where a perfectly well-formed template can be defined and then never run, because the decision to render lives somewhere other than the body itself. ## Diagnosing it in three steps 1. Fetch the mapping back from the running WireMock instance and look for the transformer name inside the `response` object. If it is absent, that is the whole bug. 2. If it is present, compare the spelling with WireMock's `response-template` character by character; a near miss registers no transformer and produces exactly the same symptom. 3. If both are right, check how the instance was launched — a mapping that quietly relies on `--global-response-templating` behaves differently on a WireMock instance that never got the flag.
- Where exactly does the transformers array go in a WireMock JSON stub mapping?Inside the `response` object, alongside `status` and `body` — not at the top level of the mapping and not inside `request`. WireMock reads transformer names off the response definition, because templating is a property of the reply, so a correctly spelled array in the wrong place is ignored in silence and looks identical to having forgotten it.
- Does WireMock templating apply to anything other than the response body?Yes — with the `response-template` transformer attached, WireMock renders response header values as well as the body, so a stub can echo a correlation id from the request into a reply header. Matching is untouched: the request pattern that selects the stub is evaluated before any rendering happens.
- What is the risk of turning on WireMock's --global-response-templating everywhere?Every response on that WireMock instance is then parsed as Handlebars, including bodies that contain braces for their own reasons. A fixture that is itself a template, or a document with `{{` in it, stops coming back verbatim. Global templating is right when the whole set is dynamic and a liability when it is mixed.
saying these in an interview costs you the question
- Assumes WireMock renders any body that contains double braces
- Puts a WireMock mapping transformers array beside the response, not inside it
- Thinks an unrendered template makes WireMock fail the request
- Spells the transformer responseTemplate and expects WireMock to resolve it
- Believes templating changes which WireMock stub matches the request