In WireMock, what does withRequestBody(equalToJson(...)) require of a request body?
answer
- structural, not textual
- parsed on both sides before comparing
- strict by default in WireMock
- two flags: array order, extra elements
- invalid JSON never matches at all
basics
~20 sIn WireMock, withRequestBody(equalToJson(...)) parses the request body as JSON and requires it to equal your expected document exactly. Extra fields, missing fields and reordered arrays all make it miss. Two optional flags relax extra elements and array order.
solid answer
~40 sIn WireMock, `equalToJson(` is a *structural* comparison rather than a string one: the body is parsed and compared with the expected document you supplied, so pretty-printing and object key order are irrelevant but the content is not. By default it is strict, so a peatland carbon-survey POST to `/carbon/v1/surveys` that adds a `clientVersion` field your expected document never mentions will not match, and neither will one that omits `siteId` or sends `readings` in a different order. WireMock's three-argument form, `equalToJson(json, true, true)`, switches on `ignoreArrayOrder` and `ignoreExtraElements`; in a mapping file those are sibling keys of `equalToJson`. A body that is not valid JSON never matches at all, because WireMock has no string fallback here. When only one field decides the response, WireMock's `matchingJsonPath(` is usually the better tool than a relaxed whole-document comparison.
go deeper
Be able to write withRequestBody(equalToJson(...)) on a WireMock stub and say what it demands: a parsed JSON body equal to the expected document, with formatting and key order irrelevant.
Explain the mechanics: WireMock parses both sides, arrays are ordered so order counts, types are part of the value, and the three-argument overload exposes the only two tolerances there are.
Show when strict whole-document matching is the wrong instrument, and be ready to justify ignoreArrayOrder per endpoint rather than switching it on everywhere out of habit.
Own the default your teams write stubs against and the review rule that goes with it, including who is allowed to pin a whole payload and what that commits the team to maintaining.
## What "equal" means to WireMock's `equalToJson(` WireMock's `equalToJson(` is a **structural** JSON comparison. When a request arrives, WireMock parses the body into a JSON tree and compares it with the tree parsed from the expected document you passed in. Everything that follows is a consequence of that one design decision: - Formatting is irrelevant. Indentation, line breaks and spacing are gone before the comparison. - Object key order is irrelevant, because a JSON object is an unordered set of members. - Array order **is** relevant by default, because a JSON array is ordered. - Numbers compare as numbers, so `-12` and `"-12"` are different; type is part of the value. - A body that fails to parse as JSON does not match. WireMock does not fall back to string equality. ## The default is strict, and strict means strict The peatland carbon-survey API in this leaf accepts a submission at `POST /carbon/v1/surveys`: ```json { "siteId": "PEAT-114", "readings": [ { "plotId": "PLOT-7", "waterTableCm": -12 } ] } ``` A WireMock stub written as `post(urlPathEqualTo("/carbon/v1/surveys")).withRequestBody(equalToJson(expected))` matches a body with exactly those members and nothing else. Each of the following stops it matching, and every one of them is a change a real client makes without telling you: - the survey app starts stamping a `clientVersion` field into every submission; - the app stops sending `waterTableCm` for a plot with no standing water; - the `readings` array arrives sorted by plot instead of by sample time; - `waterTableCm` arrives as the string `"-12"` rather than the number `-12`. The first and third of those are the ones the tolerance flags exist for. The second and fourth are not, and that asymmetry is the single most useful thing to know about this matcher. ## The two tolerance flags WireMock's `equalToJson(` has a three-argument overload, `equalToJson(String json, Boolean ignoreArrayOrder, Boolean ignoreExtraElements)`: - In WireMock, `ignoreArrayOrder` removes the significance of position inside arrays, so `readings` may arrive in any sequence. - In WireMock, `ignoreExtraElements` forgives content present in the arriving body but absent from your expected document, which turns the comparison into "the expected document is contained in what arrived". In a WireMock mapping file the same two knobs are sibling keys of `equalToJson` rather than positional arguments: ```json { "request": { "method": "POST", "urlPath": "/carbon/v1/surveys", "bodyPatterns": [ { "equalToJson": { "siteId": "PEAT-114" }, "ignoreExtraElements": true, "ignoreArrayOrder": true } ] }, "response": { "status": 202 } } ``` ## The same job in the other two servers This is where attribution matters, because the three servers start from different defaults for the same mechanism: | Server | Default for a JSON body matcher | How you change it | |---|---|---| | WireMock | strict: `equalToJson(` requires the documents to correspond | pass `ignoreExtraElements` and `ignoreArrayOrder` | | MockServer | tolerant: `json(` uses `MatchType.ONLY_MATCHING_FIELDS` | pass `MatchType.STRICT` | | Mountebank | depends on the predicate you choose from its eleven | `equals` compares what you named, `deepEquals` the whole structure | Reading that table the wrong way round is a real interview trip-hazard: someone who learned MockServer first will expect a WireMock `equalToJson(` to ignore fields it was not told about, and someone who learned WireMock first will expect MockServer's `json(` to be strict. Neither default is wrong; they are simply opposite. ## How to pick the matcher, in order 1. Decide what actually selects the response. If it is one or two fields, use WireMock's `matchingJsonPath(` and stop. 2. If the shape of the whole document is the point, use WireMock's `equalToJson(` with `ignoreExtraElements` on, so additive upstream changes do not break the stub. 3. Turn WireMock's `ignoreArrayOrder` on only where the API itself treats order as insignificant. Turning it on reflexively hides a real ordering bug. 4. Leave both flags off only when the exact payload is the thing under test and a reviewer agrees. ## Traps worth naming - Believing WireMock's `equalToJson(` compares raw strings, and worrying about whitespace. - Believing it ignores unmentioned fields. That is MockServer's default, not WireMock's. - Expecting a non-JSON body to fall back to a text comparison; in WireMock it simply does not match. - Assuming WireMock's `ignoreExtraElements` also forgives fields the client stopped sending. It does not. - Reaching for a relaxed whole-document matcher when a single WireMock `matchingJsonPath(` would say exactly what the stub means. The short version a candidate should be able to give under time pressure: WireMock's `equalToJson(` parses both sides and demands they correspond, the two flags relax additions and ordering only, and everything else about the payload is still an assertion the stub is making.
- Where do ignoreArrayOrder and ignoreExtraElements go in a WireMock JSON mapping file?They are sibling keys of WireMock's `equalToJson` inside the same body pattern object, not nested under it and not positional. The mapping form and the Java three-argument overload express the same thing, so a stub recorded to disk and a stub written in code behave identically.
- Does a WireMock equalToJson stub care whether the request declares a JSON content type?The matcher itself works on the body: it tries to parse what arrived and fails to match if it cannot. If you also want to require the header, add that as a separate header predicate on the stub. Relying on a content type to imply the body shape is how a stub ends up matching a payload nobody meant it to.
saying these in an interview costs you the question
- Says equalToJson compares the body as a raw string
- Thinks WireMock ignores fields the expected document omits
- Expects a non-JSON body to fall back to text comparison
- Believes object key order affects the comparison
- Assumes ignoreExtraElements also forgives missing fields