Skip to main content

Collection and Request Lifecycle

This page explains the two levels of Hen execution:

  1. how a collection is prepared
  2. 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:

  1. collection-level scalar assignments
  2. selected environment overrides
  3. explicit CLI --input key=value values
  4. prompt defaults
  5. runtime captures and callback exports from earlier requests

After the preamble, each --- starts a request block.

Request lifecycle

A request block usually contains:

  1. a request title
  2. a target line such as GET https://example.com
  3. request-local directives, headers, query params, forms, and body
  4. assertions
  5. captures
  6. 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:

  1. resolve variables, prompts, and any dependency values needed by the request
  2. build the request target, headers, query params, forms, and body
  3. execute the request
  4. expose the response through & ...
  5. evaluate assertions against that response
  6. apply captures to export values for later requests
  7. 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:

  1. Create user runs first
  2. its response is exposed through & ...
  3. its capture exports $USER_ID
  4. Load user can then use that captured value

verify vs run

  • hen verify checks the collection structure without executing requests or callbacks
  • hen run executes requests, exposes responses through & ..., applies captures, and runs callbacks