← Back to Blog

How to Mock an API Response on macOS with Map Local

· 8 min read

The endpoint you depend on returns the wrong shape. A field is missing, a status the docs promise is not implemented yet, or the whole route is still a 501 stub. You cannot ship your screen against that, and filing a backend ticket means waiting a day for a response you already know the shape of.

You do not have to wait, and you do not have to fake it in application code. With Map Local in Rockxy, you point one URL at a local JSON file on disk, and your app receives that file as the response instead of whatever the live server sends. The outcome of this guide: hit your real API, get back the exact payload you wrote — the documented success contract, a 500 error body, an empty list — with no backend change and no debug build.

Why mock at the proxy instead of in code

The usual instinct is to short-circuit the request inside the app: a hard-coded stub, a feature flag, a commented-out fetch. That works, but it changes the thing you are trying to test. Your networking layer, retry logic, JSON parsing, and error handling never run against the mocked payload — you have tested a different code path than production takes.

Map Local intercepts the response, not the call. The request still leaves your app with its real headers, the client still parses a real HTTP reply, and only the body (and, where configured, the status) comes from your file. You are exercising the actual code path with a payload you control. Because the swap happens in the proxy, nothing in your source changes and there is nothing to remember to revert before you commit.

What you will need

  • Rockxy on macOS 14 (Sonoma) or later. It is a native app; download it from the Rockxy download page.
  • The app or client whose request you want to override, already routing through Rockxy so the flow appears in the traffic list.
  • The exact request URL you want to mock — method and path — so the rule matches only what you intend.
  • A local JSON file with the payload you want returned. A plain .json file anywhere on disk is enough to start.
  • For an HTTPS target: that host inside Rockxy's SSL Proxying scope with certificate trust in place, so the proxy can rewrite a decrypted body rather than a tunnel.

Step 1 — Capture the request you want to override

Run your app and trigger the call once so the real flow lands in Rockxy's traffic list. You want the genuine request in front of you — the full URL, the method, and the real response — before you replace anything. Copy the URL from the selected flow; that is what your Map Local rule will match.

Doing this first means the rule matches the request your client actually sends, query string and all, instead of a URL you guessed at. If the flow does not appear at all, the request is not reaching the proxy yet — the localhost capture guide covers the loopback case, and How to Debug HTTPS Traffic on macOS covers decryption.

Step 2 — Write the fixture file

Create the JSON you want your app to receive. Match the contract your screen expects — the same field names and types the frontend reads — but put whatever values exercise the state you are building. To test an error screen, write the error body your app should render:

// ~/mocks/orders-empty.json
{
  "orders": [],
  "total": 0,
  "page": 1
}

Keep each fixture in a file you can find again — a mocks/ directory alongside the project works well. One file per state (empty list, full list, malformed field, error body) lets you switch what the endpoint returns by pointing the rule at a different file.

Step 3 — Add a Map Local rule

Open Map Local in Rockxy and enable it. Add a rule with the + control, set the match to the target URL you copied in Step 1, and point the rule's local path at the JSON file from Step 2. Map Local can serve a single file for one URL, or a local directory mapped to a path prefix when you want to mock several routes at once.

Once the rule is enabled and matching, the next matching request is served from disk. Your client still sends its request across the network — headers and all — but the body it reads back is your file. Map Local rewrites the response after the request goes out, which is why request-side headers and any server-side logging of the call still reflect a real outbound request.

Step 4 — Simulate a slow backend (optional)

A mock that returns instantly hides timing bugs — spinners that never render, requests that race, timeouts you never hit locally. Map Local's Delay Response setting holds the mocked reply before it is delivered, so you can watch how your UI behaves while the "server" is thinking.

Presets cover No Delay, 1s, 2s, 3s, 5s, 10s, 30s, 60s, and Random 1–15s, plus a Custom value from 0 to 300 seconds. Use a fixed 5s to confirm a loading state appears, Random 1–15s to shake out race conditions, or a long custom delay to force a client-side timeout and check the error path. The delay applies to the mocked response, so you test slow-network behavior without touching a real slow server.

What you should see in Rockxy

Trigger the request again. In the traffic list, the flow for your target URL now returns the body from your file rather than the live payload — an empty orders array where the server would have sent real rows, for the example above. Select the flow and the response pane shows your fixture verbatim; if you set a Delay Response, the timing reflects the wait you configured. The screenshot below shows a Map Local rule serving a local JSON file in place of the live response.

Rockxy's Map Local editor on macOS showing a rule that matches an API URL and points it at a local JSON file on disk, with the response pane rendering the mocked payload instead of the live server body.
A Map Local rule serving a fixture from disk in place of the live response — the app hits its real endpoint and reads back the JSON file you control.

Now iterate. With Auto-Save, edits to the fixture file are picked up on the next request, so you can tweak a field in your editor and re-trigger the call without touching the rule. Right-click a rule for Show in Finder or Open with to jump straight to the file you are editing. That loop — edit file, re-run request, read result — is how you shape the mock against the real screen in seconds.

When responses depend on the request

A static file cannot vary by request. If you need the mock to reflect an incoming header, a path parameter, or a request-body value — return a different user for a different id, echo an Authorization claim back — a fixed fixture is the wrong tool. For request-dependent responses, Rockxy's scripting can generate the reply dynamically from the incoming request. That is a separate feature; start with the Map Local docs and follow the scripting reference from there. For everything that does not vary per request — which is most UI-state testing — a plain fixture file is simpler and enough.

If it does not work

The rule is enabled but the live response still comes back. The match is not hitting your request. Compare the rule's URL against the exact URL in the captured flow — a trailing slash, a query parameter, or http vs https is enough to miss. Copy the URL from the flow rather than typing it.

You see a tunnel row and no rewritten body on an HTTPS target. Map Local can only replace a body the proxy can read. If the host is not in SSL Proxying scope, or the certificate is not trusted, the connection stays an encrypted tunnel and there is nothing to override. Add the host to SSL Proxying and confirm trust — the HTTPS debugging guide walks through it.

A pinned host never decrypts. If the app pins its certificate, Rockxy will not silently defeat that — the handshake fails and surfaces as a failed transaction in the request list. You cannot Map Local a response you were never able to decrypt. Test against a build without pinning, or mock at a layer the app trusts.

Your edited fixture is not reflected. Confirm the rule points at the file you are editing — right-click and use Show in Finder to be sure — and that Auto-Save is picking up changes on a fresh request rather than a cached one. Trigger the call again after saving.

Limitations to keep in mind

A mocked response does not reach the real server — Map Local answers from disk, so no row is created, no side effect fires, and no backend state changes. That is the point when you are building a screen, but it means Map Local is not a substitute for an integration test against the real API. For an HTTPS endpoint, the host must be decryptable (in SSL Proxying scope, certificate trusted, not pinned) or the proxy only sees a tunnel and cannot rewrite anything. And a static fixture is fixed: the same file for every matching request until you edit it or switch the rule.

Next steps

Map Local turns a stuck screen into a solved one: write the JSON your UI is supposed to render, point one rule at it, and your app receives that payload from its real endpoint. Add a Delay Response to test loading and timeout states, keep a fixture per state to switch what the endpoint returns, and reach for scripting only when the reply has to vary by request.

From here, read the Map Local documentation for directory mapping and status overrides, get decryption working first with How to Debug HTTPS Traffic on macOS, or see the technique applied end to end in Advanced Flutter API Debugging on macOS. If capture itself is behaving oddly, the FAQ covers the most frequent setup questions.

Rockxy — native macOS proxy debugger

Try Rockxy — Free and Open Source

A native macOS proxy debugger for HTTP, HTTPS, WebSocket, and API traffic. No cloud account. No subscription. Download the app or audit the source directly on GitHub.

Open source · AGPL-3.0 · Native macOS · No account required · Source available to audit