In WireMock, what does aResponse().withBase64Body() serve that withBody(String) cannot?
answer
- a String body goes through a character encoding
- text encodings do not preserve arbitrary bytes
- the mapping stays text, the body does not
- it decodes, it does not encode
- WireMock withBase64Body or withBodyFile
basics
~20 sIt serves raw bytes. WireMock's withBase64Body takes a base64-encoded string and decodes it into the exact body bytes, so a binary payload such as a signed watering permit survives, while withBody takes text that must go through a character encoding.
solid answer
~50 sWireMock's `withBody(String)` writes text: the string is turned into bytes through a character encoding, and a byte sequence that is not valid in that encoding is not preserved. That rules it out for a binary allotment watering permit, an image or a compressed rota export. WireMock's `withBase64Body(String)` takes the payload already base64-encoded and decodes it back to the exact bytes it serves, so the mapping stays a text document while the reply is arbitrary binary. The other route for the same problem is WireMock's `withBodyFile(`, which reads the bytes from a file instead of carrying them in the mapping. Base64 wins when the payload is small and the mapping should stay self-contained; a file wins when the payload is large or somebody needs to open it. Either way, set the media type yourself with WireMock's `withHeader(`.
code
java · 7 linesbyte[] permit = Files.readAllBytes(Path.of("src/test/resources/plot-17-permit.pdf"));
stubFor(get(urlPathEqualTo("/allotment/rota/plots/17/permit.pdf"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/pdf")
.withBase64Body(Base64.getEncoder().encodeToString(permit))));go deeper
Know that WireMock has a body setter for bytes as well as text: withBase64Body takes an already-encoded string and serves the decoded bytes, while withBody is for text payloads only.
Explain the mechanism: a String body goes through a character encoding, so arbitrary bytes are not preserved. Say what base64 buys and what it costs in mapping size and readability.
Show that you have hit the silent-corruption failure and know why it hides: the status is right, the length looks plausible, and only a real parser downstream complains.
Decide where binary fixtures live across a stub set, how they are produced from real artefacts rather than typed by hand, and how large a payload may be before it must become a file.
## The problem base64 solves A stub mapping is a text document. A response body is a sequence of bytes. Those two facts sit comfortably together while the body is JSON or XML, and collide the moment an allotment water-rota API is asked for something that is not text — a signed watering permit as a PDF at `GET /allotment/rota/plots/17/permit.pdf`, a compressed export of the season's rota, a small image. WireMock's `withBody(String)` is the text route. The string you pass is turned into body bytes through a character encoding, and that conversion is only faithful for byte sequences the encoding can represent. Round-tripping arbitrary binary through a Java `String` is therefore lossy: bytes that are not valid in the encoding are substituted rather than preserved, and the client receives a payload that is the right length and the wrong content. The failure is quiet, which is what makes it worth knowing — the stub returns 200, the test asserts on a status code, and the corruption shows up later as a parser error nobody can reproduce. ## What withBase64Body does WireMock's `withBase64Body(String)` takes the payload **already base64-encoded** and decodes it, serving the decoded bytes as the body. Base64 is a text encoding of arbitrary bytes, so: - the mapping stays a plain text document that a JSON file or a Java source file can hold; - the bytes on the wire are exactly the bytes you encoded, with no character-set conversion in the path; - the stub remains self-contained — there is no companion file to ship with it; - the cost is size, because base64 is meaningfully larger than the bytes it encodes. The direction matters and is the most common misunderstanding: WireMock's `withBase64Body(` **decodes**. You hand it encoded text; it does not encode for you. ## The two binary routes, compared | approach | where the bytes live | good for | cost | |---|---|---|---| | WireMock `withBase64Body(` | inside the mapping, as base64 text | small payloads, self-contained stubs | larger mapping, unreadable body | | WireMock `withBodyFile(` | a file the server reads | large payloads, files people open | the fixture must travel with the stub | Both are WireMock's; they are alternatives, not a sequence. A useful way to choose: if a human will ever want to look at the payload, put it in a file. If nobody will, and it is small, base64 it into the mapping and keep the stub one object. ## Getting the rest of the reply right A binary body does not change the other parts of a WireMock response definition, and each still has to be set: 1. **Status** — WireMock's `withStatus(200)`, or whatever the real permit endpoint answers. 2. **Media type** — WireMock's `withHeader("Content-Type", "application/pdf")`. A client that dispatches on media type will mishandle correct bytes announced as nothing. 3. **Body** — WireMock's `withBase64Body(` with the encoded payload. Encode the fixture once, from a real file, rather than typing base64 by hand. In a test, reading the bytes and encoding them at set-up time keeps the fixture honest, because the thing you encode is the thing on disk. ## When not to reach for it - **When the body is text.** JSON base64-encoded into a mapping is unreadable for no gain; use WireMock's `withBody(` and keep it legible. - **When the payload is large.** A megabyte of base64 inside a mapping makes the stub set unreviewable, and the file route exists precisely for this. - **When you are trying to hide an awkward payload.** If the reply is hard to write because the real service is hard to model, base64 buries the problem instead of solving it. ## What interviewers listen for - That you can say *why* a `String` body is wrong for binary — character encoding, not size — and that the corruption is silent. - That you get the direction right: WireMock's `withBase64Body(` decodes an encoded string; it is not an encoder. - That you name the alternative and choose between them on payload size and whether anyone reads the bytes. - That you still set the media type, because a correct binary body announced with no `Content-Type` fails just as loudly as a corrupted one. A candidate who says "binary bodies go through `withBase64Body(` in WireMock, or a file, and never through a `String`" has the whole of this mechanism.
- Why is a corrupted binary body from a WireMock String stub so hard to notice?Because everything above the bytes looks healthy. WireMock answers 200, the body has a plausible length, and a test asserting on status or size passes. The damage only surfaces when something actually parses the payload, often in a different suite or a manual check, with no obvious link back to the stub that produced it.
- When would you prefer WireMock's withBodyFile() over withBase64Body() for binary?When the payload is large, or when a person will want to open it. A file keeps the mapping small and lets somebody view the permit or image directly. Base64 is better for a small payload where keeping the stub a single self-contained object matters more than anyone reading the bytes.
saying these in an interview costs you the question
- Thinking withBase64Body encodes the argument for you
- Passing raw binary through withBody as a String
- Believing corruption would obviously fail the test
- Base64-encoding a JSON body for no reason
- Omitting Content-Type because the body is binary