Skip to content

Add fault-proxy: single-file GraphQL fault-injection proxy#4

Open
ria8651 wants to merge 1 commit into
mainfrom
add-fault-proxy
Open

Add fault-proxy: single-file GraphQL fault-injection proxy#4
ria8651 wants to merge 1 commit into
mainfrom
add-fault-proxy

Conversation

@ria8651

@ria8651 ria8651 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

A tiny, zero-dependency Node reverse proxy for manual testing of the typed
GraphQL error + connection-lost banner work in open-msupply
PR #11444
(and the #11885 long-delay work).

It sits between the client and the real omSupply server, streams traffic
through unchanged, and lets you flip failure modes live from a control panel
(/__proxy) or over curl — without touching the server.

Modes

mode on the wire client result
pass forward unchanged healthy
offline destroy the socket, no HTTP response NetworkError → ConnectionLostBanner / Page
http500 HTTP 500, empty body NetworkError (transport-failure HTTP branch)
internal / unauthenticated / forbidden / badinput HTTP 200 {errors:[…]} the matching typed error
partial forward real data, graft errors[] onto it typed error thrown despite present data
delay forward, held back by delayMs slow / "startup in progress" path

Knobs: scope (graphql-only / all), count (fault next N then auto-revert),
delayMs, detail. All settable from the panel or as query params.

Why it exists / relationship to #2

This is a deliberately separate, single-file take alongside James's
#2. They converged
on the same architecture independently; the strengths are complementary:

  • This one is one drop-in file with true streaming passthrough, a working
    first-class delay mode, a unique partial (errors + data) mode, and
    honest upstream-down behaviour (drops the socket rather than returning a
    proxy 502).
  • Add GraphQL fault-injection proxy (node + Python) #2 adds per-operation / per-path targeting and curated presets that hit
    the QueryErrorHandler silent-permission-path and long-detail-toast edge
    cases, plus truncate and a mitmproxy variant.

Opening both so we can pick one — or fold the per-operation/per-path targeting
from #2 onto this engine.

Test steps

Manual-test helper, no automated tests.

  1. Run the real server on :8000 (cd server && cargo run).
  2. node fault-proxy/fault-proxy.js (proxy :8001:8000).
  3. cd client && yarn start --env API_HOST=http://localhost:8001.
  4. Open http://localhost:8001/__proxy, flip modes, confirm the client
    reacts (banner on offline, re-login on unauthenticated, toast on
    internal, etc.).

Notes

  • Dev/manual-test tool — no auth on the control plane, which shares the
    data-plane port. Localhost-only.
  • Injected responses carry credentials-aware CORS headers so the browser can
    read them with credentials: 'include'.

🤖 Generated with Claude Code

A single-file Node reverse proxy that sits between the omSupply client and
server and injects error/connectivity states that are hard to reproduce by
hand: socket drop (NetworkError + connection banner), HTTP 500 no body,
typed GraphQL errors (Unauthenticated / Forbidden / Bad user input /
Internal error), errors-plus-partial-data, and a configurable response
delay. Built to exercise the typed-error + connection-banner work in
open-msupply PR #11444 (and the #11885 long-delay work).

Streams in passthrough mode, falls back to dropping the socket if the real
upstream is down, and ships a live control panel at /__proxy plus a
curl-friendly query/JSON API. No dependencies; Node 18+.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant