Collection and Request Lifecycle
This page explains the two levels of Hen execution:
- how a collection is prepared
- what happens when a request runs
Collection lifecycle
Everything before the first --- is the preamble.
That is where you declare global collection values such as:
- scalar variables
- prompt placeholders
- secret-backed values
- arrays
- named environments
- collection-wide defaults such as reliability settings
name = Example Collection
$ API_ORIGIN = https://api.example.com
$ API_KEY = secret.env("HEN_API_KEY")
$ USER_ID = [[ user_id ]]
env local
$ API_ORIGIN = http://localhost:3000
Before a run starts, Hen prepares the collection by resolving those inputs in order:
- collection-level scalar assignments
- selected environment overrides
- explicit CLI
--input key=valuevalues - prompt defaults
- runtime captures and callback exports from earlier requests
After the preamble, each --- starts a request block.
Request lifecycle
A request block usually contains:
- a request title
- a target line such as
GET https://example.com - request-local directives, headers, query params, forms, and body
- assertions
- captures
- optional callbacks
Get user
GET {{ API_ORIGIN }}/users/{{ USER_ID }}
* Authorization = Bearer {{ API_KEY }}
^ & status == 200
& body.id -> $FETCHED_USER_ID
! ./scripts/notify.sh
What & means
After a request runs, Hen exposes the response through the & accessor space.
That response can be used in:
- assertions
- captures
- dependency captures
Examples:
^ & status == 200
^ & body.user.name == "alice"
& body.user.id -> $USER_ID
& header.content_type -> $CONTENT_TYPE
The most common response roots are:
& status& body& header
So when you write:
^ & status == 200
you are asserting against the response from the request that just executed.
Order of operations for one request
At a high level, Hen handles a request in this order:
- resolve variables, prompts, and any dependency values needed by the request
- build the request target, headers, query params, forms, and body
- execute the request
- expose the response through
& ... - evaluate assertions against that response
- apply captures to export values for later requests
- run callbacks
Callbacks run after request execution, which makes them a good fit for notifications, post-processing, or local side effects.
Dependencies extend the lifecycle across requests
When one request depends on another, the earlier request must complete first:
Create user
POST {{ API_ORIGIN }}/users
~~~json
{"name":"alice"}
~~~
^ & status == 201
& body.id -> $USER_ID
---
Load user
> requires: Create user
GET {{ API_ORIGIN }}/users/{{ USER_ID }}
^ & status == 200
In that flow:
Create userruns first- its response is exposed through
& ... - its capture exports
$USER_ID Load usercan then use that captured value
verify vs run
hen verifychecks the collection structure without executing requests or callbackshen runexecutes requests, exposes responses through& ..., applies captures, and runs callbacks