skip to content

In WireMock, how do you regenerate a committed mapping set by re-pointing recordSpec().forTarget( at the live meter API?

level: seniorimportance: should knowfreq 64%

answer

  1. a re-run, not a first capture
  2. the target host changes, the suite does not
  3. WireMock record spec takes a base URL
  4. forTarget re-points the proxy leg
  5. regenerate beside the committed set, then diff

basics

~20 s

Point a fresh WireMock recording at the live district heating meter API with forTarget, replay the same traffic, and let the recorder write a new mapping set. Then diff that set against the committed one rather than overwriting it blindly.

solid answer

~40 s

A refresh is a re-run of the recorder against an already-recorded set, not a first capture. In WireMock you build a record specification and hand it a new base URL — `recordSpec().forTarget("https://meters.stadtwaerme.example")` — so the proxy leg now reaches the live district heating meter API rather than whatever host the original capture used. You then drive the same client calls the committed set covers, such as `GET /v1/meters/{meterId}/readings`, and WireMock regenerates mappings from what actually came back. Write the regenerated set somewhere other than WireMock's working `mappings/` directory so the committed files survive, then diff the two: the delta is the whole point of the exercise. Mountebank's `--removeProxies` performs the equivalent last step, stripping the proxy stubs out of the configuration it writes so a later run replays only recorded responses.

code

java · 18 lines
java
import static com.github.tomakehurst.wiremock.client.WireMock.*;

// standalone instance started with --root-dir refreshed/ so the
// committed mappings/ directory is never written to
configureFor("localhost", 8081);

startRecording(
    recordSpec()
        .forTarget("https://meters.stadtwaerme.example")
        .makeStubsPersistent(true)
);

// drive exactly the calls the committed set was built to answer
meterClient.meter("DE-HH-4471");
meterClient.readings("DE-HH-4471", "2026-01-01", "2026-01-31");
meterClient.substationFlow("HH-NORD-12");

stopRecording();

go deeper

for a junior

Be ready to say what the recorder does at all: it proxies a call to a real service and turns the response it saw into a stub mapping. Know that WireMock's record specification takes a target base URL.

for a middle

Explain the mechanics of a re-run: forTarget names the live host for this capture, the regenerated mappings land under a root directory you choose, and the committed set must stay untouched so the two can be compared.

for a senior

Show the judgment that separates a refresh from a re-record. Talk about replaying the exact traffic the committed set covers, recording against production rather than staging, and never writing over the baseline you intend to diff against.

for a principal

Own the question of how often this runs, who reads the diff, and what happens to hand edits that regeneration flattens. Argue for or against automating the refresh at all, given it costs real calls against a service you do not own.

## What a refresh is, and what it is not A committed stub set is a photograph of an upstream service taken on the day somebody recorded it. **Refreshing** is taking that photograph again against the service as it stands today, and comparing the two prints. The distinction matters because a first capture and a refresh have different deliverables: a first capture produces *a mapping set*, a refresh produces *a difference*. If you finish a refresh holding nothing but a new pile of JSON files, you have performed a first capture with extra steps. In WireMock the machinery is the record specification, and the single control that turns a re-run into a refresh is `forTarget(`. WireMock's `recordSpec().forTarget("https://meters.stadtwaerme.example")` names the live base URL the recorder proxies to, so the same client code that normally talks to the stub server now reaches the real district heating meter API and every response is captured on the way back. Your test code does not change; only the host behind the proxy leg does. ## The four moves of a refresh 1. **Stand a second WireMock instance on a clean root.** Start `wiremock-standalone` with `--root-dir refreshed/` so its `mappings/` and `__files/` directories begin empty. The committed set stays untouched on disk, which is the whole reason a diff is possible afterwards. 2. **Re-point the recorder.** WireMock's `recordSpec().forTarget("https://meters.stadtwaerme.example")` aims the proxy leg at the live meter API for this run. Pair it with WireMock's `makeStubsPersistent(true)` so the regenerated mappings are written as files rather than held only in memory. 3. **Replay the traffic the committed set covers.** Drive the real client rather than hand-rolled curl calls: the point is to reproduce the exact requests the committed mappings were built to answer, headers and query parameters included. 4. **Stop and diff.** WireMock's `stopRecording()` closes the capture, and the delta between `refreshed/mappings/` and the committed WireMock `mappings/` directory is the artefact you came for. ## What to drive during the replay - Every request path the committed set answers — `GET /v1/meters/{meterId}`, `GET /v1/meters/{meterId}/readings`, `GET /v1/substations/{substationId}/flow`. - The parameter variants the committed set distinguishes, such as a readings window that spans a tariff change and one that does not. - The error paths you can safely provoke, such as an unknown `meterId` that the live meter API answers with `404`. - Nothing that mutates real state. A refresh that posts readings into the production meter API is a write against a system of record, not a recording. ## Where the controls live | control | product | what it does in a refresh | |---|---|---| | `recordSpec().forTarget(url)` | WireMock | aims the proxy leg at the live meter API for this run | | `makeStubsPersistent(true)` | WireMock | writes each regenerated mapping under `mappings/`, extracted bodies under `__files/` | | `--root-dir` | WireMock standalone | chooses which directory that is, so the committed set is not overwritten | | `withProxyUrlPrefixToRemove(` | WireMock | strips a local path prefix before the request reaches the upstream host | ## The traps - **Refreshing against staging.** A capture taken from a staging deployment of the meter API describes staging. If the question is whether the committed set still matches production behaviour, staging cannot answer it. - **Overwriting in place.** Running the recorder against WireMock's working `mappings/` directory destroys the baseline in the same moment it produces the candidate, and the diff is gone before anyone reads it. - **Losing hand edits.** Real committed sets are rarely raw recordings: matchers get loosened, volatile fields get relaxed, names get tidied. Regeneration produces raw output again, so those edits must be reapplied deliberately rather than assumed to survive. - **Recording through your own gateway.** If the client's base URL carries a local prefix the upstream does not have, the captured URLs will be wrong. In WireMock `withProxyUrlPrefixToRemove(` is the control for that. - **Assuming a clean diff means nothing changed.** It can equally mean the replay never exercised the part of the API that changed. ## Why the diff, not the set, is the deliverable The regenerated set is evidence, not a release. Read it as three separate questions. Which mappings are **new** — calls the client now makes that the committed set never covered? Which are **missing** — paths the replay did not reach, which is usually a gap in the replay rather than in the API? And which have the **same request but a different response**? Only the third group can be a genuine change in the upstream, and even there most entries will be volatile values rather than shape changes. So treat the diff as a review artefact with a human reader. Commit the parts you accept, reapply the hand edits the raw recording flattened, and leave the rest of the committed set exactly as it was. A refresh that ends in a wholesale directory replacement has thrown away every deliberate decision the set accumulated since the first capture, and it will do so silently.

  • The refreshed set has no mapping for a path the committed set covers. Is that an upstream removal?
    Usually not. The far commoner cause is that your replay never made the call, so the recorder had nothing to capture. Confirm by checking whether the client exercised that path during the run before you conclude the meter API dropped it. Only after the replay demonstrably reached the path is a missing mapping evidence about the upstream rather than about your replay coverage.
  • Why not refresh straight into WireMock's working mappings/ directory and rely on version control for the diff?
    Because WireMock names regenerated files with a generated suffix, so the new files rarely land on top of the old ones — you get additions plus orphans rather than a readable per-file diff. Recording into a clean root keeps the two sets whole, so you can normalise and compare them as sets instead of trusting filename collisions to line them up.

saying these in an interview costs you the question

  • Thinks refreshing means deleting mappings/ and recording from scratch
  • Overwrites the committed set in place, so the diff is lost
  • Ships the regenerated set without reading the delta
  • Points the recorder at staging and calls it a production refresh
  • Assumes re-recording preserves matchers that were hand-loosened later