Develop without the real backend
bowire mock turns any captured recording into a live endpoint at the same shape as the original. Same protocols, same payloads, same timing — just a JSON file driving it.
The third-party API needs an OAuth flow + a paid subscription? Your own backend is a 12-container docker-compose with a 5-minute boot time? The mainframe replicates a real-DB-only-on-Tuesdays integration test? A captured recording cuts all of that out of the dev / test loop — the fixture is the JSON file.
When the real thing is too expensive to spin up
Three concrete cases where the real backend is more friction than the development is worth.
- The real API costs money to hit. Stripe / Twilio / Salesforce / OpenAI / Mapbox — every call against a paid SaaS burns API credits or trips a per-call billing line. Local dev shouldn't have to choose between “run tests against staging and worry about the bill” or “skip the test, hope it works”. A recording-driven mock replays the API's responses for free against your dev runs, while the real call is reserved for the actual production traffic.
- The real backend takes 10 minutes to boot. Some service stacks need a database migration, a message broker, a primary + replica, an identity provider, three queue workers, and a debug agent before the first request goes through.
docker-compose upworks, but it's not a dev-loop primitive.bowire mock --recording session.bwr --port 5099boots in milliseconds against the same response shape. - The real backend isn't reachable. Air-gapped CI runners, offline development on a flight, a third-party API behind a corporate VPN you don't have today — the recording is a portable artefact. Drop it on a USB stick, drop it in a Git repo, hit replay.
Same idea regardless: your dev / test loop shouldn't be gated on the production-grade backend being available. The recording is the testable surface.
flowchart LR
Test(["Dev / test loop"])
Real(["Real backend"])
Mock(["bowire mock"])
BWR[("session.bwr")]
Local(["localhost:5099"])
Test -.->|"without mock"| Real
Real -.-> Bill(["per-call billing"])
Real -.-> Compose(["10-min docker-compose boot"])
Real -.-> VPN(["VPN-only access"])
Test ==>|"with mock"| Mock
Mock --> BWR
BWR --> Local
bowire mock turns the captured .bwr into a local endpoint at the same protocol shape — instant, free, fully offline.What the mock actually does
Not a JSON-stub generator. Every byte the mock serves is what the real server sent during the capture — gRPC frames, WebSocket messages, MQTT publishes, REST bodies, all preserved at the protocol level.
Every protocol your recording captured replays through the same listener — REST verbs on the same paths, gRPC unary + server-streaming + bidi with the captured frames, WebSocket / SSE / SignalR / Socket.IO pushing the same sequence, MQTT publishes on the same topics, GraphQL subscriptions streaming the same events. Status codes, frame timing, headers all stay intact; nothing collapses to a JSON stub.
Optional layers on top:
- Hot-reload — rewriting the recording file refreshes the mock without restart.
- Chaos injection — configurable latency / 5xx rate / dropped-frame ratio for resilience tests.
- Schema-only mode —
--from-spec openapi.yamlserves plausible responses from an OpenAPI / gRPC descriptor / GraphQL schema with no recording at all. - Stateful cursors — a recording with multiple captures of the same call replays them in order, so the fifth call sees the fifth response.
- Capture-on-miss — unrecorded request transparently forwards to a fallback target, captures the response, serves it back next time. Useful for incrementally growing a mock as your test suite grows.
From recording to mock to CI
One artefact (the .bwr recording) drives interactive replay in the workbench, headless replay via bowire mock, and the security scanner via bowire scan. Same file, three consumers.
Workflow that lights up: capture a real session against staging (or against the third-party API once, with their key) → commit the .bwr file to your repo next to the test fixtures → CI brings up bowire mock --recording fixtures/api.bwr --port 5099 alongside the integration tests → tests run against the mock, deterministic and offline. The real backend stays untouched.
For dev: same recording, run bowire mock on your laptop, point your frontend / scripted client at http://localhost:5099. No staging-account creation, no credentials in .env files committed by accident, no waiting for the integration team to provision a sandbox.
The DevOps workflow page walks the full pipeline: mock-as-fixture → integration tests → security scan → SARIF upload — all from the same captured recording.
Cut the backend out of the dev loop
Capture once, replay anywhere. No real-backend account, no real-backend credits, no real-backend boot time.
A different lane fits better? All solution lanes →