Skip to content

Scripts

lex edited this page Aug 6, 2026 · 2 revisions

Scripts & Assertions

Pre-Request Scripts (< {% %})

Run before the HTTP request is sent. Used to compute variables, log, or perform side effects.

Syntax

Single-line:

< {% request.variables.set("ts", tostring(os.time())) %}

Multi-line:

< {%
  local token = "Bearer " .. request.variables.get("auth_token")
  request.variables.set("auth_header", token)
  client.log("Set auth header")
%}

External file:

< ./scripts/preprocess.lua

Script Sandbox API

Object API Description
request.variables .set(name, value) Inject @name = value into request
request.variables .get(name) Read request-level variable value
request.headers .set(name, value) Set request header
request.headers .get(name) Get request header
request.body (string) Request body content
client.global .set(name, value) Persist variable across requests
client.global .get(name) Read persisted variable
client.log (msg) Log message (visible in Script tab)
env (name) Read environment variable
variables (name) Read resolved variable
md5 .sum(str) Compute MD5 hash

Example: Compute HMAC-style signature

< {%
  local ts = tostring(os.time())
  request.variables.set("timestamp", ts)
  local sig = md5.sum("secret-key-" .. ts)
  request.variables.set("signature", sig)
%}
POST https://api.example.com/data
X-Timestamp: {{timestamp}}
X-Signature: {{signature}}

{"key": "value"}

Example: Chain multiple variables

< {%
  local name = request.variables.get("username")
  request.variables.set("greeting", "Hello, " .. name .. "!")
  request.headers.set("X-Greeting", "Hello, " .. name .. "!")
  client.log("Processing user: " .. name)
%}

Post-Request Assertions (> {% %})

Run after the HTTP response is received. Used to validate response status, body, headers.

Syntax

Single-line:

> {% client.test("ok", function() client.assert(response.status == 200) end) %}

Multi-line:

> {%
  client.test("Status is 200", function()
    client.assert(response.status == 200, "Expected 200, got " .. response.status)
  end)
  client.test("Has data", function()
    client.assert(#response.body > 0, "Body is empty")
  end)
%}

External file:

> ./scripts/verify.lua

Assertion Sandbox API

Object API Description
response .status HTTP status code (number)
response .body Response body (string or table for JSON)
response .headers Response headers (table)
response .content_type Content-Type header value
response .latency_ms Response time in milliseconds
response .url Final URL after redirects
client .test(name, fn) Register a named test
client .assert(cond, msg) Assert condition (throws on failure)
client .log(msg) Log message
client.global .set(name, value) Persist variable across requests
client.global .get(name) Read persisted variable
request.variables .get(name) Read request variable
env (name) Read environment variable
variables (name) Read resolved variable
md5 .sum(str) Compute MD5 hash
assert (cond, msg) Standard Lua assert

Example: Validate JSON response

POST https://api.example.com/users
Content-Type: application/json

{"name": "Alice", "email": "alice@example.com"}

> {%
  client.test("Created", function()
    client.assert(response.status == 201, "Expected 201")
  end)
  client.test("Has ID", function()
    client.assert(response.body.id ~= nil, "Missing id field")
  end)
  client.test("Email matches", function()
    client.assert(response.body.email == "alice@example.com", "Email mismatch")
  end)
  client.log("User created with ID: " .. response.body.id)
%}

Example: Chain from response

> {%
  client.test("Auth success", function()
    client.assert(response.status == 200, "Auth failed")
  end)
  if response.status == 200 then
    client.global.set("token", response.body.access_token)
    client.global.set("refresh", response.body.refresh_token)
  end
%}

Request Orchestration (SCRIPT blocks + client.run)

A request block whose request line is SCRIPT runs as a script-only block. When the block also has a post-script (> {% ... %}), its Lua body executes as an orchestration script: client.run() calls imported requests like functions, and the returned responses can be inspected and chained into later calls.

Syntax

import ./requests.http as api

### Login then fetch profile
SCRIPT
> {%
  local login = client.run("#api.Login", { username = "alice", password = "secret" })
  assert(login.status == 200, "login failed")

  local profile = client.run("#api.GetProfile", { auth_token = login.body.token })
  assert(profile.status == 200, "get profile failed")
  client.log("profile: " .. profile.body.username)
%}

client.run(target, args)

Part Description
target #Name or #alias.Name, resolved through the file's import directives
args Lua table of named values. Converted to HTTP strings (tables → JSON) and injected as @var overrides; the target request references them via {{name}}
returns Typed response object (see below)

The typed response exposes:

  • status, status_text, url, latency_ms, content_type, cookies, metadata
  • headers — case-insensitive access (r.headers["Content-Type"])
  • body — lazily JSON-decoded table, or the raw string when the body is not JSON

Execution model

  • Requests run sequentially; the script suspends until each client.run call completes.
  • Every call's response is rendered in the multi-response chain (navigate with ] / [ in the response buffer).
  • client.log(msg) / print(...) output goes to the Script Logs tab.
  • assert / client.assert(cond, msg) abort the script on failure; client.test(name, fn) works like assertion blocks.
  • A request failure or unresolved target raises inside client.run and aborts the script with the target name; the error is shown in the Assertions tab.

Example: loop + verification

### Register 3 users
SCRIPT
> {%
  local ids = {}
  for i = 1, 3 do
    local user = client.run("#api.RegisterUser", {
      name = "user_" .. math.random(1000, 9999),
      age = math.random(18, 60),
    })
    assert(user.status == 201, "register failed")
    ids[#ids + 1] = user.body.id
  end
  local all = client.run("#api.ListUsers", {})
  assert(all.body.count >= 3, "list users failed")
  client.log("created ids: " .. table.concat(ids, ", "))
%}

Editor support

  • gd on #api.Login jumps to the request block in the imported file.
  • Completion inside client.run(" offers # / #alias. request names, same as run #.
  • Targets are highlighted like run directives (#api. prefix + request name).
  • K on client.run shows the API documentation.

A runnable demo lives in the playground: playground/http/scenarios/orchestration_demo.http.

Results Display

Assertion results appear in the Assertions tab of the response buffer:

✓ 3 passed, 0 failed

A Status is 200: ✓
A Has data: ✓
A Email matches: ✓

Pre-script logs appear in the Script tab. Assertion failures show the error message inline.