In WireMock, why can PUT /__admin/mappings/{id} lose parts of the stub you meant to keep?
answer
- replacement, not a patch
- the whole mapping goes in the body
- read it back before you change it
- WireMock 4 data classes are immutable
- transform on the old StubMapping
basics
~20 sWireMock stores what you send to PUT /__admin/mappings/{id} as the whole mapping under that id. It is a replacement, not a patch, so any matcher missing from your body is gone. Read the mapping first, then put it back complete.
solid answer
~50 sThe route replaces the mapping held under that id with the document you send; it does not merge your fields into what is already stored. Send a body containing only the field you meant to change and everything else that mapping carried — the extra request matchers, the response headers, the scenario wiring — disappears with it, and the stub then matches far more or far less traffic than before. The safe pattern is read-modify-write: `GET` the mapping from WireMock's `/__admin/mappings/{id}`, change the one field **in the document you received**, then `PUT` that complete document back to the same id. WireMock 4 states the same discipline in Java by making the core data classes immutable with builders: in WireMock 4 `stubMapping.setRequest(x)` is gone, and you write `oldStubMapping.transform(b -> b.setRequest(x))` — derive a whole new mapping from the old one rather than poke one field.
code
bash · 13 lines# the id WireMock returned when this lighthouse stub was registered
ID=8f0c4d2e-6b21-4d5a-9a77-0c2f1b3e4a55
# 1. read the whole mapping back
curl -s "http://localhost:8080/__admin/mappings/$ID" > lamp.json
# 2. change one field IN THE DOCUMENT YOU RECEIVED
jq '.response.status = 503' lamp.json > lamp-degraded.json
# 3. put the COMPLETE mapping back under the same id
curl -s -X PUT "http://localhost:8080/__admin/mappings/$ID" \
-H 'Content-Type: application/json' \
--data @lamp-degraded.jsongo deeper
Remember that the id in /__admin/mappings/{id} addresses one whole mapping, and that sending a body there swaps that mapping out. Do not think of it as editing a single field.
Explain the mechanics: WireMock stores your body as the complete definition under that id, so omitted matchers and response fields vanish. Describe the read-modify-write loop as the fix.
Diagnose the silent version of this: a stub that suddenly matches too much because an edit dropped a matcher. Connect it to WireMock 4's immutable data classes and the transform-from-the-old-object pattern.
Set the convention for how live stub definitions are changed across teams — read-modify-write only, or replace-and-recreate — and make sure the tooling people copy encodes it rather than leaving each author to rediscover it.
## What WireMock actually stores at that route WireMock's `PUT /__admin/mappings/{id}` takes the document in your request body and makes it the mapping held under that id. The stored mapping is replaced wholesale. WireMock is not comparing your body field by field against what it already has and merging the differences; it is taking what you sent as the definitive definition of that stub from now on. That one sentence explains every surprise this route produces. If your body carried a single field, the mapping now has a single field's worth of definition. Everything else the stub used to say about which lighthouse requests it matched, and what it answered them with, is not "unchanged" — it is absent. ## Why "partial update" is the wrong mental model The mental model that causes the bug is the one borrowed from configuration systems that merge: send the delta, and the rest persists. Applied here it produces a stub that quietly changes shape. Suppose a mapping for the lighthouse maintenance API matched `GET /lighthouses/BEACHY-HEAD/lamp` **and** required a tenant header, and answered 200 with a body and a content type. Someone wants it to answer 503 for a failure scenario and PUTs a body carrying only the new status. The result is a mapping with no header requirement and no response body. The failure is worse than an error would be: - The stub now matches requests it was meant to reject, because the header matcher went with the rest of the body. - The reply is no longer the shape the client parses, because the response definition was replaced by a bare status. - Nothing fails at the moment of the PUT. The call succeeds; the damage shows up as a confusing mismatch later, possibly in a different test. - If two mappings overlapped deliberately, the surviving one now competes differently for the same traffic. - A colleague reading the test sees the PUT body and reasonably assumes the rest of the mapping is still there. ## The read-modify-write loop The operating rule is to never build a PUT body from scratch around the field you care about. Instead: 1. `GET` WireMock's `/__admin/mappings/{id}` and keep the document you get back — it is the complete current definition. 2. Change the one field you mean to change **inside that document**, leaving everything else exactly as it came. 3. `PUT` the whole modified document back to the same id. 4. Read it back once if the edit matters, so the stub you believe in is the stub the server holds. This is slower to type than a one-line PUT and it is the only form that is safe, because it treats the mapping as an object with an identity rather than a bag of settings. ## WireMock 4 says the same thing in Java The HTTP discipline has an exact counterpart in the library. WireMock 4 made the core data classes — including `StubMapping` and `ResponseDefinition` — **immutable, with builders**. The mutator many people remember, `stubMapping.setRequest(x)`, no longer exists. You derive a changed copy instead: In WireMock 4: `oldStubMapping.transform(b -> b.setRequest(x))` That is not a stylistic preference; it is the same rule the route enforces. You take the whole existing mapping, express the change against it, and end up with a complete new mapping. An engineer who understands why `transform` replaced the setter already understands why a partial PUT body is a defect. ## What to check when a stub "stopped working after an edit" When a lighthouse suite passes before an edit and fails after one, walk the difference rather than the symptom: - Compare the mapping now stored under that id with what the suite believes it registered. - Ask whether the PUT body was assembled from a read of the current mapping or written by hand. - Look specifically for matchers that are absent rather than wrong — an absent matcher widens a stub silently, while a wrong one usually produces a visible mismatch. - Check whether the id you PUT to is the id you meant; putting a complete mapping to the wrong id replaces a stub you were not editing at all. - Remember that WireMock's `DELETE /__admin/mappings/{id}` and a fresh `POST /__admin/mappings` are an alternative to editing when the new definition shares nothing with the old one — but that combination gives you a new registration, not the same one modified. ## The rule in one line On WireMock's admin API, `{id}` addresses a whole mapping and a `PUT` to it swaps that mapping out. Treat the mapping as the unit of change, read before you write, and the surprises stop. Every field you omit is a decision, whether or not you meant to make one.
- What is the safest way to change one field of a live WireMock mapping?Read the mapping with `GET /__admin/mappings/{id}`, edit the document you received, and `PUT` the complete result back to the same id. Never assemble the PUT body from scratch around the field you care about: whatever you leave out is gone, because the route stores what you send as the whole mapping.
- How does WireMock 4's immutability change Java code that edits a StubMapping?`stubMapping.setRequest(x)` no longer exists — the core data classes are immutable with builders, so you derive a new mapping from the old one with `oldStubMapping.transform(b -> b.setRequest(x))`. The discipline is identical to the HTTP one: take the whole existing object, change what you mean to change, and end up with a complete replacement.
saying these in an interview costs you the question
- Treats PUT /__admin/mappings/{id} as a partial patch
- Sends only the changed field and expects a merge
- Thinks WireMock 4 still lets you mutate a StubMapping in place
- Edits a mapping without reading the current one first
- Blames the matcher when the replacement body dropped it