Skip to main content

Guide

Chain API requests and pass response values forward

Real API tests are rarely one request. You log in, capture what the login returned, and prove the next call works with it. In APIWeave that is one graph: requests wired in order, with the values between them handled by extractors and variables rather than copy-paste.

The problem

Copy-pasting a token between runs is not a test

A chained workflow captures the value once and reuses it, so the same test runs unattended against any environment.

Login → token → authenticated call
HTTP Request: POST /login
  body: { "username": "{{env.USER}}", "password": "{{secrets.APP_PASSWORD}}" }
  -> 200 OK { "access_token": "eyJhbGciOi...", "expires_in": 3600 }

Extractor:
  name = token
  path = response.body.access_token

Next node: GET {{env.BASE_URL}}/orders
  Authorization: Bearer {{variables.token}}

Three things make that exchange safe to run repeatedly:

  • The password is a secret reference, so the value is never written into the workflow.
  • The token is captured by an extractor with a JSONPath, not typed in — a fresh token per run is the point.
  • The next request reads the variable, so a rotation in the login response needs no edit downstream.

Requests run in graph order, and an Assertion node can sit between them: pin the status equals 200 on the login before anything downstream runs, so a broken authentication fails at the node that broke.

Mechanisms

Four ways to move a value between nodes

Pick by how far the value has to travel and how many branches need it.

Which mechanism to use for each request-chaining situation
You need to…UseBecause
A token or session ID that every later call needsExtractor → workflow variableIt is captured once at the login node and reused by every downstream request, so the value is not re-derived per call.
A single next step that needs the whole previous responseThe prev namespace{{prev.response.body.field}} reads the immediately upstream node with no extractor to maintain.
A value one branch of a fan-out needsExtractor or prev[index] after the mergeAfter a Merge, an unindexed prev reference is ambiguous. The index names the branch explicitly.
A request the API rejects without a token the client cannot sendCall Workflow with input and output mappingsThe sub-workflow resolves its own secrets and environment; only workflow variables need mapping.

Extractors: capture once, use anywhere downstream

An extractor is a name and a pathattached to an HTTP Request node. After the node runs, the captured value is a workflow variable available to every later node in the same run. Add one straight from a response you already have: open the node's response tree, hover the row, and choose Save as variable. The row then keeps a chip showing which variable it feeds.

Paths always start with response. and use dot notation with zero-based array indices:

  • response.statusCode
  • response.headers.content-type
  • response.headers.set-cookie
  • response.body.id
  • response.body.user.id
  • response.body.items[0].id
  • response.body.data[2].tokens[0]

What an unresolved reference does

If a placeholder cannot be resolved — a misspelled namespace, a key no environment defines, an extractor that never matched — the runner leaves the literal {{...}}text in the field instead of stopping the run. The run records the unresolved reference per node, so the exact missing key is visible in the results. In an assertion's expected value, that surfaces as a template problem rather than a value mismatch.

The most common cause is the namespace typo: {{variable.token}} (singular) does not match the variables.* namespace. The second most common is a path that does not match the real response shape — check the actual body for the field name, including its case.

Branches

Chain across parallel branches and merges

One login can feed two independent calls, captured once and reused by both.

One token, two downstream branches
[ Start ] -> [ POST /login ] -> [ Assertion: status == 200 ]
                              |
                              +-> [ GET /orders ]  (with {{variables.token}})
                              +-> [ GET /profile ] (with {{variables.token}})
                              |
                         [ Merge: all ] -> [ Assertion: order count == 3 ] -> [ End ]
Reading a branch after a Merge
# Inside the node after the Merge, index the branch you want.
{{prev[0].response.body.id}}     # first branch, in canvas order
{{prev[1].response.body.id}}     # second branch

# The branch index is zero-based and follows the order the branches sit
# on the canvas, not the order they finished.

After a Merge node, a plain {{prev.response.body.id}} is ambiguous, because several branches converged. Index the branch you mean: indices are zero-based and follow canvas order.

A Merge also chooses how much of the graph waits. The all strategy waits for every branch before continuing, which is what a chained test usually wants; any and first continue on the first completion, and a conditional merge continues based on per-branch conditions you configure.

If you reference a branch that never completed, the placeholder stays as literal text. Confirm the branch count and order from the run results before indexing.

Reuse

Reuse the login instead of chaining past it

When several workflows all start with the same authentication, make it a step rather than a prefix.

A reusable authentication step
[ Start ] -> [ Call Workflow: Authenticate ] -> [ POST /cart ] -> [ End ]

Call Workflow node:
  input mapping:   tenant    = {{variables.tenantId}}
  output mapping:  authToken = accessToken

The caller then uses {{variables.authToken}} in its own request headers.
  • The sub-workflow runs inline, inside the caller's run. There is no second entry in run history; the calling node's result carries the summary.
  • It shares the run's environment and secrets, so {{env.*}} and {{secrets.*}} resolve in the sub-workflow without mapping.
  • Only workflow variables need mapping in or out, because each execution keeps its own variable map.
  • A {{secrets.NAME}} on the right-hand side of an input mapping fails the node by design. Let the sub-workflow read the secret itself.

Limits

What chaining does not do

Knowing the edges saves a debugging session. These are the real ones.

A secret reference cannot be used in a request URL
Placeholders work in headers, cookies, bodies, query parameters, and assertion expected values. A {{secrets.*}} placeholder is refused in the URL field, so keep credentials in a header or body.
An assertion's path is not templated
Placeholders resolve in request fields and in an assertion's expected value. The assertion path itself is taken literally, as are the HTTP method and timeout.
A token inside a GraphQL string has nowhere safe to go
A GraphQL query is sent as the request body, and arguments inside that query string are not interpolated as placeholders. APIWeave does not have a GraphQL-aware request node.
Secrets are not inherited and not synced
The scope chain is environment then workspace, both local. Inheritance passes plain variables only, and a synced workflow resolves {{secrets.NAME}} against the store on the machine that runs it.

New to the canvas? Start with the five-step walkthrough, then come back to chaining.