File-Backed Responses
Some bodies don’t want to live inside a JSON file. A PDF export can’t be written as JSON at all; a 200 KB captured payload turns a mock into something nobody can read; a SOAP envelope hand-escaped into a JSON string is impossible to diff. response_file points a mock at a file next to it and serves that file’s exact bytes.
{ "method": "GET", "path": "/reports/:id/export", "status": 200, "response_file": "fixtures/report.csv", "response_headers": { "Content-Disposition": "attachment; filename=\"report.csv\"" }}curl -i http://localhost:8080/reports/9/export# HTTP/1.1 200 OK# content-type: text/csv; charset=utf-8# content-disposition: attachment; filename="report.csv"## id,name,plan,seats,mrr# 1,Acme Corp,enterprise,250,12500Binary works the same way, byte for byte:
{ "method": "GET", "path": "/users/:id/avatar", "status": 200, "response_file": "fixtures/avatar.png"}Where the file is looked up
Section titled “Where the file is looked up”The path is resolved relative to the mock file’s own directory, not to the working directory — so a mocks tree stays relocatable and a Docker volume mount works unchanged:
mocks/└── advanced/ ├── get_report_export.json → "response_file": "fixtures/report.csv" └── fixtures/ ├── report.csv ├── invoice.xml └── avatar.pngA path that resolves outside the mocks root — ../../etc/passwd, an absolute path, or a symlink pointing out of the tree — is refused at load time with an error naming the mock file, and that mock is not registered.
Content type
Section titled “Content type”The first of these wins:
Content-Typein the mock’s ownresponse_headers;- the file extension:
.json,.xml,.csv,.html,.txt,.png,.jpg/.jpeg,.pdf,.zip; application/octet-stream.
A .json fixture is served as a JSON body, not as a JSON-quoted string.
Templating (opt-in)
Section titled “Templating (opt-in)”Set "template": true to interpolate {{path.*}}, {{query.*}}, {{header.*}}, {{body.*}}, and {{faker.*}} inside the file — the same expressions a response supports (see Response Templating):
{ "method": "POST", "path": "/soap/invoices/:id", "status": 200, "template": true, "response_file": "fixtures/invoice.xml"}<InvoiceId>{{path.id}}</InvoiceId><Currency>{{query.currency}}</Currency><CustomerRef>{{body.customer_ref}}</CustomerRef>Templating is off by default and never runs on a binary content type, so a PNG that happens to contain the bytes {{ is still a PNG.
Sequences
Section titled “Sequences”A sequence step takes the same two fields, so a retry flow can end in a real file:
{ "method": "GET", "path": "/flaky-export", "status": 200, "sequence": [ { "status": 503, "response": { "error": "unavailable" } }, { "status": 200, "response_file": "fixtures/report.csv", "repeat": true } ]}Semantics
Section titled “Semantics”responseandresponse_fileare mutually exclusive. A mock setting both is a load error naming the file. Setting neither is unchanged behavior (response: null).- Files are read at load time and re-read on every hot reload cycle, so editing a fixture takes effect within ~2s without touching the mock file. Request handling never touches the disk.
MIMIC_MAX_RESPONSE_FILE(default 10 MB) caps one fixture. A file over the cap is reported and its mock is skipped rather than half-loaded;0removes the cap.- A
.jsonfixture is not loaded as a mock. The loader reads every mock file under the mocks directory, but a file some mock claims as itsresponse_fileis served, never registered. - The request log stores a text body verbatim (truncated at
MIMIC_MAX_RECORDED_BODY) and a binary body as a one-line descriptor —<70 bytes of image/png from fixtures/avatar.png>— so the dashboard stays readable. - Everything else composes as usual: path parameters, matchers,
delay_ms, tags, and CORS all work with a file-backed body.