Skip to content

Structural Blocks

A .bridge file is constructed entirely from top-level structural blocks. There are four primary types of blocks you will use to build your dataflow graph: bridge, tool, define, and const.

A bridge block is the main entry point for a single GraphQL field. It acts as the routing blueprint, wiring a specific GraphQL operation to its underlying data sources.

bridge Query.getUser {
with std.httpCall as api
with input as i
with output as o
api.userId <- i.id
o.name <- api.fullName
}

The Bridge enforces strict scoping. Before you can read from or write to a dependency inside a bridge body, you must bring it into scope using the with keyword.

DeclarationWhat it provides
with myTool as tA new instance of a tool. Write to it via t.param, read its result via t.result.
with input as iThe GraphQL query arguments (e.g., i.argName).
with output as oThe GraphQL return type. Writing to o.fieldName shapes the final API response.
with context as ctxThe server execution context (e.g., auth tokens, request headers).
with const as cAccess to named constants declared in the file.
with myDefine as dA reusable define block (macro).

If your underlying tool’s output shape perfectly matches your GraphQL return type, you can skip the wiring body entirely.

# The HTTP response is returned directly to the client as-is
bridge Query.getRawData with myTool

This is incredibly useful for building zero-boilerplate proxy endpoints.

Tool blocks allow you to pre-configure reusable API calls or transform functions. While a bridge block handles the logic for a specific GraphQL endpoint, a tool block represents the external service itself.

You declare a new tool using the tool <Name> from <BaseTool> syntax:

tool hereGeo from std.httpCall {
with context
# Tool Configuration
.baseUrl = "https://geocode.search.hereapi.com/v1"
.method = "GET"
.path = "/geocode"
# Pull the API key dynamically per-request
.headers.apiKey <- context.hereApiKey
}

You can provide a safe fallback value in case the tool throws an error (like a network timeout or a 500 response).

tool fragileApi from std.httpCall {
.baseUrl = "https://unstable.example.com"
# Return a safe default instead of failing the GraphQL request
on error = { "lat": 0, "lon": 0 }
}

Tools can extend other tools. This is a powerful way to organize your API clients, allowing you to define a base configuration and spawn specific endpoints from it.

tool baseApi from std.httpCall {
with context
.baseUrl = "[https://api.example.com](https://api.example.com)"
.headers.Authorization <- context.token
}
tool baseApi.users from baseApi {
.path = "/users"
.method = "GET"
}
tool baseApi.createUser from baseApi {
.path = "/users"
.method = "POST"
}

const blocks define global, static JSON values that are accessible across all bridges and tools in the file. They are perfect for configuration, magic numbers, or shared fallback objects.

const maxRetries = 3
const fallbackGeo = { "lat": 0, "lon": 0 }
const config = {
"timeout": 5000,
"endpoints": ["US", "EU"]
}

To access them in your graph, bring them into scope: with const as c, then wire them using dot notation: o.lat <- c.fallbackGeo.lat.

Defines are reusable subgraphs. Think of them as macros that get inlined into your bridge at parse time. They are ideal for standardizing common data mapping patterns across multiple endpoints.

1. Create the Define:

define secureProfile {
with userApi as api
with input as i
with output as o
api.id <- i.userId
# Map the raw API fields to our standard schema
o.name <- api.login
o.email <- api.email
}

2. Use it in a Bridge:

bridge Query.me {
# Bring the macro into scope
with secureProfile as profile
with input as i
with output as o
profile.userId <- i.id
o.name <- profile.name
}