Fallbacks & Resilience
When wiring external data sources, you must account for missing data and network failures. The Bridge engine handles this natively without requiring imperative try/catch or if/else blocks.
Instead, it relies on a 3-Layer Architecture that gives you surgical control over exactly how and when your APIs fail.
1. Layer 1: Safe Execution (?.)
Section titled “1. Layer 1: Safe Execution (?.)”By default, if a tool throws a network exception (e.g., HTTP 500, timeout), the error bubbles up and crashes the GraphQL field.
To gracefully handle I/O failures, you use the Safe Execution Modifier (?.), perfectly mirroring TypeScript’s Optional Chaining. Appending ?. tells the engine: “If this tool throws an error, or the data is missing, swallow the error and return undefined.”
# STRICT: If the billing API crashes, the field crashes.o.receipt <- billingApi.charge
# SAFE: If the avatar API crashes, swallow the 500 error and yield `undefined`.o.avatar <- avatarApi?.urlStrict Path Traversal (The ?. Nuance)
Section titled “Strict Path Traversal (The ?. Nuance)”To ensure API contracts are respected, path traversal in The Bridge behaves exactly like standard TypeScript. Where you place the ?. matters immensely.
Consider these two lines:
o.out <- user?.info.nameo.out <- user.info?.name
If the user API is called but the backend returns a completely empty object {}, here is how the engine responds:
- Scenario 1:
.infoevaluates safely toundefined. We then attempt to access.namestrictly. The engine throws aTypeErrorand crashes the field! - Scenario 2:
.infois accessed strictly, resulting inundefined. The?.onnameintercepts the subsequent structural crash and safely yieldsundefined.
If the user API throws a 500 Network Error:
- Scenario 1: The
?.is on the root tool. It intercepts the network crash and yieldsundefined. - Scenario 2: The root tool is evaluated strictly. The network error crashes the field!
2. Layer 2: Data-Level Routing (|| and ??)
Section titled “2. Layer 2: Data-Level Routing (|| and ??)”Once Layer 1 resolves the data (or yields undefined), the engine evaluates Data Routing gates to determine what value to pass down the wire.
When you chain multiple sources together, the engine evaluates them left to right, sequentially. It stops and short-circuits at the very first acceptable result. Sources to the right of the winner are never called.
The Falsy Gate (||)
Section titled “The Falsy Gate (||)”The || operator triggers if the left side is falsy (0, "", false, null, undefined).
# If the user has no nickname, or it is an empty string "", fall back to "Guest".o.displayName <- userApi?.nickname || "Guest"The Nullish Gate (??)
Section titled “The Nullish Gate (??)”The ?? operator triggers only if the left side is exactly null or undefined. It respects 0, "", and false as valid data.
# If the user's balance is exactly $0, we WANT to show 0.# We only fall back if the data is actually missing.o.walletBalance <- billingApi?.balance ?? -13. Layer 3: Wire-Level Catch (catch)
Section titled “3. Layer 3: Wire-Level Catch (catch)”The || and ?? operators do not catch network errors. If a strict tool throws an HTTP 500, it blows past the data routing gates entirely.
If you want to provide an absolute, final safety net for the entire wire in case any strict evaluation fails, use the catch keyword.
# 1. Evaluate B strictly.# 2. If it is nullish, evaluate C strictly.# 3. If B or C throw a 500 network error, catch it and return "Error".o.value <- B.field ?? C.field catch "Error"The catch fallback is evaluated only if an unhandled exception occurred during the execution of that specific wire.
4. Raising Explicit Errors
Section titled “4. Raising Explicit Errors”Sometimes a fallback isn’t enough, and you actively want to break the execution flow based on business logic. The Bridge provides explicit control flow keywords to seamlessly bridge the gap between declarative mappings and GraphQL’s robust error-handling spec.
Field Error (throw)
Section titled “Field Error (throw)”Fails the specific output field, but allows the rest of the graph to continue evaluating. This maps perfectly to a standard GraphQL partial error in the errors array.
# If the API is missing data or crashes, throw a domain-specific erroro.receipt <- billingApi?.charge ?? throw "Billing system unavailable"Fatal Error (panic)
Section titled “Fatal Error (panic)”Stops all engine processing immediately and fails the entire request. This acts exactly like an external client disconnect (AbortSignal) and results in a top-level error (e.g., HTTP 403/500).
o.secureData <- authApi.token ?? panic "CRITICAL: Unauthorized access"5. Cost-Aware Overdefinition
Section titled “5. Cost-Aware Overdefinition”What happens if you define multiple completely separate lines to target the exact same field?
o.city <- i.cityo.city <- geoApi.cityNameThis is called Overdefinition. Instead of throwing a syntax error or blindly racing all the sources in parallel, the engine forms an implicit coalesce group and sorts them by estimated execution cost.
Cost Tiers
Section titled “Cost Tiers”| Cost Tier | Sources | Why |
|---|---|---|
| Free (0) | input, context, const, alias | Pure memory reads. Zero I/O overhead. |
| Computed (1) | Tool calls, Pipes, Defines | Require scheduling and possible network I/O. |
Cheapest-First Resolution
Section titled “Cheapest-First Resolution”When a target is overdefined, the engine evaluates the sources cheapest first:
- It tries all Free (Cost 0) sources.
- If they all return
nullorundefined, it moves to Computed (Cost 1) sources. - It stops and returns the very first non-nullish result it finds.
(Note: The engine respects falsy values like 0, "", and false. If a cheap source returns 0, the engine accepts it and short-circuits, saving the cost of evaluating the more expensive sources.)