skip to content

Literal Bodies and Files

A status, response headers and a body written inline, read from a file on disk or carried as base64, plus Mountebank's defaultResponse filling the gaps. Interviewers check where the file is read from.

on this pageshow

explore

questions

4

In WireMock, what does aResponse().withBase64Body() serve that withBody(String) cannot?

level: middleimportance: must knowfreq 46%

answer

  1. a String body goes through a character encoding
  2. text encodings do not preserve arbitrary bytes
  3. the mapping stays text, the body does not
  4. it decodes, it does not encode
  5. WireMock withBase64Body or withBodyFile

basics

~20 s

It 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 s

WireMock'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 lines
java
byte[] 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

for a junior

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.

for a middle

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.

for a senior

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.

for a principal

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
open as a page

When should a WireMock stub's water-rota body move from withBody() to withBodyFile()?

level: seniorimportance: must knowfreq 58%

basics

~20 s

Move it once the payload buries the matcher, when several mappings need the same fixture, or when the bytes want to be a real file. WireMock's withBodyFile names a file under __files, leaving the mapping with the matcher and status.

open as a page

Your WireMock water-rota stub returns valid JSON but the client refuses to parse it — why?

level: seniorimportance: must knowfreq 55%

basics

~20 s

Almost always the stub set a body and no media type. In WireMock the reply carries only the headers the response definition declares, so a client that checks Content-Type before decoding rejects a perfectly correct body. Add withHeader explicitly.

open as a page

In WireMock, what do aResponse(), withStatus() and withBody() each set on a stubbed reply?

level: juniorimportance: should knowfreq 68%

basics

~20 s

In WireMock, aResponse() starts the response builder, withStatus sets the numeric HTTP status, and withBody sets the literal reply body as text. WireMock adds response headers separately, through withHeader. Nothing in the reply is inferred from the request.

open as a page