SpecRunner Documentation

Build, test, and automate API workflows visually

Access this page from the landing hero via the “View Docs” button (next to “Open Editor”). The docs open in a new tab so you can keep the editor in view while you experiment.

1. Visual Flow Builder

Drag nodes from the palette, pan/zoom freely, and wire outputs to inputs. Rename nodes in the inspector, search/collapse the palette, and toggle Dormant to temporarily disable nodes without rewiring. When you double-click the canvas or drop a node from the palette, a quick-add picker appears exactly where you clicked.

  • Resizable side panel plus collapsible/searchable node list.
  • Inline node controls (eye icon) blur dormant nodes and mark them as skipped during execution.
  • Light/dark theme toggle affects the whole workspace.
  • Double-click canvas / drag out of the palette to open the node quick-add menu right where you need it.
  • Node cards display their ID with a one-click copy action; IDs match those shown in logs/variables.
  • Keyboard shortcuts: R to run, Esc deselects,⌘/Ctrl + S quick-saves, and (upcoming) Delete removes the selected node.

2. Node Types

HTTP Node

Send REST requests with templated URLs, headers, and JSON bodies. Responses can be persisted into shared variables, optional retry policies help stabilize flaky endpoints, and request previews/exporters (JSON, cURL, wget) keep your inspector in sync with real tooling.

POST https://api.example.com/login
Headers:
  Content-Type: application/json
Body:
{
  "email": "dev@example.com",
  "password": "{{ variables.password }}"
}
Persist response body → alias: loginResponse

Extract Node

Copy a JSON value from the prior node (or any earlier node) into a named variable.

JSONPath: {{ response.body.data[0].id }}
Variable name: firstUserId

Assertion Node

Validate values using equals / exists / contains. Failing assertions halt the execution.

Type: equals
Path: {{ response.status }}
Expected: 201

Log Node

Write templated text into the debugger log—perfect for breadcrumbs or printing variables.

Message: Order {{ variables.orderResponse.id }} created

Wait Node

Pause execution for a fixed duration (up to 10 minutes).

Delay (seconds): 30

Conditional Node

Evaluate a boolean expression and branch via the green (true) or red (false) handle.

{{ response.status }} === 200
{{ response.body.message }} includes "success"
{{ variables.loginResponse.token }} isNotNull

Loop Node

Repeat a section of the flow for each item (or for a fixed count). Drop nodes inside the loop container to define the body.

Items: {{ variables.items }}
Item alias: item
Index alias: index
Max iterations: 25

Set Variable

Create or override a variable with JSON or a template value.

Variable: items
Value: [{"id":1},{"id":2}]
Value (template): {{ response.body.items }}

3. Importers & inspectors

The HTTP inspector shows JSON / cURL / wget previews and can import any of those formats. Paste a snippet and click Apply to hydrate the form, or copy the generated command directly into your terminal.

  • Preview tabs: switch between JSON, cURL, and wget to copy exactly what will run.
  • HTTP import: drop JSON that mirrors the preview, a curl -X … statement, orwget --method=… command. Headers, body, and method are parsed automatically.
  • Postman import: use the editor toolbar to import a Postman collection or environment. Collections hydrate linked HTTP + Extract nodes in order; environments map enabled variables into the Environment dialog.
  • Inspector sections include retry controls, response persistence, Monaco JSON editor, and collapsible help so the panel stays compact.

4. Node settings modal

Selecting any node opens a modal with two tabs: Settings for configuration and Runtime for the latest execution output. Run the flow to populate runtime details, and close the modal with the top right button. The Runtime tab offers a GUI view for HTTP nodes and a JSON view for full details.

Use the Skip toggle to bypass a node while still allowing downstream nodes to execute. Use Hide (Dormant) to disable a node entirely until re-enabled.

If validation fails, the Runtime tab shows a list of issues so you can fix missing URLs, paths, or assertions before running again.

5. Data flow & template scope

Every node evaluates templates inside a scope containing the latest upstream response, previous node results (`nodes[nodeId]`), and the shared `variables` object. Template examples:

{{ response.body.token }}
{{ nodes["node-123"].response.body.user.id }}
{{ variables.loginResponse.token }}
{{ env.API_TOKEN }}
{{ env.baseUrl }}

Use Extract nodes or HTTP nodes with “Persist response body” to add new entries to variables. Environment variables (set in the toolbar Environment dialog) are always reachable via {{ env.MY_KEY }}, and shared base URLs/default headers are accessible through the same env object (e.g. {{ env.baseUrl }}).

6. Environment profiles

Click the Environment button in the toolbar to define shared settings:

  • Base URL – automatically prefixes any relative HTTP node URL. Enter /orders and SpecRunner sends https://api.example.com/orders (assuming your base ishttps://api.example.com).
  • Default headers – merged into each HTTP node before its own headers; node-level values override matching keys.
  • Environment variables – arbitrary key/value pairs plus automatic entries like env.baseUrl andenv.defaultHeaders. Reference them anywhere with {{ env.API_TOKEN }} and inspect them inside the debugger’s environment block.

Environment data is saved alongside your flow (snapshots, import/export, and persistence) so switching between projects keeps the right defaults.

6. If node operators

===

Checks strict equality.

!==

Strict inequality.

includes

Substring or array membership.

isGreater / isLower

Numeric comparison (> / <).

isArray / isString / isNumber

Type guards.

isNull / isNotNull

Nullish checks.

Unary operators (isArray / isNull / etc.) ignore the right-hand value. Expressions should use spaces, e.g.{{ response.status }} isLower 400

7. Execution engine

  • Topologically sorts nodes (left → right, respecting edges).
  • Honors branch handles; nodes are skipped if their incoming branch is false or their dormant toggle is on.
  • Status colors: yellow = running, green = success, red = failed, gray = skipped/dormant.
  • Execution stops on first failure and writes detailed logs + stored variables to the debugger.
  • Enable Continue on error from the toolbar to keep executing nodes even after a failure (great for collecting all assertion results in one run).

8. Debugger & runtime

  • Logs – terminal-style stream with timestamps, inline search/highlight, and quick copy. Expand the debugger to give logs more vertical space while testing complex flows.
  • Variables – JSON view of the sharedvariables object plus per-node request/response payloads. Content wraps, so you never have to scroll horizontally.
  • Runtime tab – per-node output lives in the modal Runtime tab, with request/response payloads for HTTP nodes.

9. Persistence, import/export & UX enhancements

  • Flows persist automatically in local storage (nodes + edges).
  • Theme preference (light/dark) is saved via `useUIStore`.
  • Side panel width, palette collapse, and search help organize large projects.
  • Monaco editor adopts the current theme for consistent JSON editing.
  • Use the toolbar to Export Flow, import Postman collections/environments, or load a sample flow from the toolbar dropdown (Quick HTTP or Loop + Products).
  • Clear all resets the canvas, environment, and runtime debugger state.
  • Zoom indicator shows live zoom percentage while you pan/zoom the canvas.
  • Backend proxy routes HTTP requests through a Netlify function when enabled in the toolbar menu.
  • Postman/Insomnia export exports HTTP nodes in order; non-HTTP nodes are skipped.

10. Sample end-to-end flow

Recreate this scenario to see how nodes, branching, and variables tie together. You can also load the Loop + Products sample from the toolbar to see a loop container with HTTP + Log nodes inside.

  1. HTTP “Get user” – GET {{ env.baseUrl }}/users/{{ env.sampleUserId }}.
  2. Extract “User” – store {{ response.body }} → variables.user.
  3. HTTP “List products” – GET {{ env.baseUrl }}/products?limit=5.
  4. Extract “First product” – store {{ response.body.products[0] }} → variables.firstProduct.
  5. HTTP “Get product details” – GET {{ env.baseUrl }}/products/{{ variables.firstProduct.id }}.
  6. Assertion – {{ response.body.title }} isNotNull.
  7. Log – User {{ variables.user.username }} previewed {{ response.body.title }} (${{ response.body.price }}).