Pre-Request Hooks
A pre-request hook is a lightweight script written in Rhai that Rumour runs immediately before sending your HTTP request to the target server. It lets you programmatically inspect, modify, or validate headers, query parameters, body content, and variables without having to hardcode values in your .toml files.
Common Use Cases
- Dynamic Security & Auth: Injecting time-based authorization headers, custom signatures, or dynamic tokens.
- Request Customization: Reconstructing request payloads or query parameters based on variables.
- Logging & Observability: Printing execution context to the terminal for debugging purposes.
- Early Validation: Checking environment prerequisites (like whether a server URL is defined) and halting the run before any requests are sent if a validation fails.
How It Works
To associate a pre-request hook with your HTTP request, configure the pre_request key inside your .toml request file. Rumour supports two placements for this key:
Option A: At the Root Level
You can define pre_request directly at the root of the file:
name = "get_user_profile"
pre_request = "my_script.rhai"
[request]
method = "GET"
url = "{{base_url}}/users/1"
Option B: Within the [request] Block
Alternatively, you can place it inside the [request] table alongside request properties like method and url:
name = "get_user_profile"
[request]
method = "GET"
url = "{{base_url}}/users/1"
pre_request = "my_script.rhai"
Rumour checks for the hook at the root level first. If not defined there, it falls back to checking inside the [request] block.
File Location & Path Resolution
Rumour resolves the script path relative to the directory containing the request TOML file. This means you can keep scripts in sub-folders or parent folders by using relative paths:
- In the same folder:
pre_request = "my_script.rhai" - In a sub-folder:
pre_request = "scripts/my_script.rhai" - In a parent/sibling folder:
pre_request = "../shared/auth.rhai"
This allows you to organize and reuse scripts across multiple requests in your collection:
scripting_examples/
├── shared/
│ └── auth.rhai
└── users/
├── workspace.env.toml
└── get_user_profile.toml # Configured with: pre_request = "../shared/auth.rhai"
Relative Path Example Execution
If get_user_profile.toml is inside a users/ subdirectory and specifies pre_request = "../shared/auth.rhai", running:
Here is how the files in this setup are configured:
shared/auth.rhai
// shared/auth.rhai
log("Shared pre-request authentication script started.");
headers["Authorization"] = "Bearer token-123456";
log("Authorization header injected successfully.");
users/workspace.env.toml
# users/workspace.env.toml
base_url = "http://localhost:4000/api/v2"
users/get_user_profile.toml
# users/get_user_profile.toml
name = "pre_hook_relative_path"
[request]
method = "GET"
url = "{{base_url}}/users"
pre_request = "../shared/auth.rhai"
[assert]
status = 200
Running the Example
Executing the request in verbose mode:
rumour run ./scripting_examples/users/get_user_profile.toml -tv
Will output:
[SCRIPT] Shared pre-request authentication script started.
[SCRIPT] Authorization header injected successfully.
GET http://localhost:4000/api/v2/users
Header: Authorization: Bearer token-123456
URL: http://localhost:4000/api/v2/users
✓ SUCCESS: /home/bugsfounder/workspace/testing/scripting_examples/users/get_user_profile.toml (0ms)
✓ ./scripting_examples/users/get_user_profile.toml → PASS (1 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1 │
│ Successful: 1 │
│ Failed: 0 │
│ Skipped: 0 │
│ Success Rate: 100.0% │
│ Total Time: 1ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- /home/bugsfounder/workspace/testing/scripting_examples/users/get_user_profile.toml [200] [1ms]
Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.
Understanding the Output
Since the TOML file was at /home/bugsfounder/workspace/testing/scripting_examples/users/get_user_profile.toml, Rumour resolved ../shared/auth.rhai relative to the users/ directory, resolving to the sibling /home/bugsfounder/workspace/testing/scripting_examples/shared/auth.rhai script. The script successfully ran and injected the Authorization: Bearer token-123456 header before sending the HTTP request.
Available Variables in the Script
When your pre-request script runs, Rumour exposes four objects you can read and write:
| Object | Type | Description |
|---|---|---|
vars | Map (read/write) | All runtime variables in scope for this request |
headers | Map (read/write) | Current request headers (before sending) |
params | Map (read/write) | Outgoing query parameters of the request |
body | String (read/write) | The raw request body string |
Any changes you make to vars, headers, params, or body take effect in the actual HTTP request that Rumour sends.
Logging
You can call log("message") from any script to print a labeled message to the terminal during the run:
[SCRIPT] your message here
Example
Goal
Inspect and modify the request dynamically before sending:
- Read the
base_urlandrole_to_assignenvironment variables. - Generate a custom tracking ID and inject it into the request headers as
X-Trace-Id. - Read the original request body, modify it to use a dynamic username and the environment-defined role, and update it.
- Output debug statements during execution.
File Layout
scripting_examples/pre_request/
├── workspace.env.toml
├── get_user.toml
└── inject_headers.rhai
workspace.env.toml
base_url = "http://localhost:4000/api/v2"
role_to_assign = "admin"
get_user.toml
name = "pre_hook_post_user"
[request]
method = "POST"
url = "{{base_url}}/users"
pre_request = "inject_headers.rhai"
[body]
raw = '{"username": "temp_user_name", "role": "user"}'
type = "json"
[assert]
status = 201
inject_headers.rhai
// This script runs BEFORE the HTTP request is sent.
// You can read & modify: vars, headers, body
log("Pre-request script execution started.");
// 1. Reading and writing variables (vars)
log("Current base_url is: " + vars["base_url"]);
vars["custom_tracking_id"] = "track-123456";
log("Generated tracking ID: " + vars["custom_tracking_id"]);
// 2. Inspecting and modifying request headers
headers["X-Trace-Id"] = vars["custom_tracking_id"];
headers["X-Requested-By"] = "rumour-pre-hook";
// 3. Inspecting and replacing request body
log("Original body: " + body);
body = `{"username": "user_lead_dev", "role": "` + vars["role_to_assign"] + `"}`;
log("Modified body: " + body);
Run
rumour run ./scripting_examples/pre_request/get_user.toml -tv
Output
~/workspace/testing main* ❯ rumour run ./scripting_examples/pre_request/get_user.toml -tv
[SCRIPT] Pre-request script execution started.
[SCRIPT] Current base_url is: http://localhost:4000/api/v2
[SCRIPT] Generated tracking ID: track-123456
[SCRIPT] Original body: {"username": "temp_user_name", "role": "user"}
[SCRIPT] Modified body: {"username": "user_lead_dev", "role": "admin"}
POST http://localhost:4000/api/v2/users
Header: X-Requested-By: rumour-pre-hook
Header: X-Trace-Id: track-123456
URL: http://localhost:4000/api/v2/users
Body (json): {"username": "user_lead_dev", "role": "admin"}
✓ SUCCESS: /home/bugsfounder/workspace/testing/scripting_examples/pre_request/get_user.toml (1ms)
✓ ./scripting_examples/pre_request/get_user.toml → PASS (1 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1 │
│ Successful: 1 │
│ Failed: 0 │
│ Skipped: 0 │
│ Success Rate: 100.0% │
│ Total Time: 4ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- /home/bugsfounder/workspace/testing/scripting_examples/pre_request/get_user.toml [201] [4ms]
Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.
Understanding the Output
Let's break down exactly what the verbose output above tells us:
-
Script Logs (
[SCRIPT]):- The script execution starts before the request is dispatched.
- It reads
base_url(http://localhost:4000/api/v2) from the environment variables. - It dynamically generates a tracking ID (
track-123456). - It logs the initial request body definition before modification (
{"username": "temp_user_name", "role": "user"}). - It constructs the new modified body with the environment-configured admin role (
{"username": "user_lead_dev", "role": "admin"}).
-
HTTP Request Details:
- Method & URL: A
POSTrequest is sent to the resolved url:http://localhost:4000/api/v2/users. - Headers: Custom headers injected by the Rhai script (
X-Requested-By: rumour-pre-hookandX-Trace-Id: track-123456) are attached. - Body: The final payload sent is the modified JSON body containing the updated username and role.
- Method & URL: A
-
Status Check & Execution Report:
- The server returns status code
201(Created). - Since our assertion expects
status = 201, the request passes (✓ SUCCESS).
- The server returns status code
Modifying the Request Body
You can completely replace the request body from a pre-request script:
// replace body with a dynamically computed JSON string
body = `{"user_id": "` + vars["user_id"] + `", "timestamp": "2024-01-01"}`;
The body variable in scripts is always a plain string. If you are building JSON, construct it as a string manually. The type field in your [body] block controls how the server interprets it.
Setting Variables
You can write to vars to inject computed values downstream requests will pick up:
// Store a nonce for use in downstream requests
vars["request_nonce"] = "nonce-" + vars["user_id"];
After the hook runs, {{request_nonce}} is available to all subsequent requests in the same workflow.
Advanced Scripting Example (Control Flow, Loops, & Validation)
Below is an advanced pre-request script demonstrating:
- Validation & Aborting: Checking variable presence and throwing an error to halt the run if preconditions are not met.
- If/Else Logic: Checking environment values and conditionally modifying headers.
- Loops: Iterating over collections to construct a dynamic, structured JSON body representation.
advanced_flow.toml
name = "pre_hook_advanced_flow"
[request]
method = "POST"
url = "{{base_url}}/users"
pre_request = "advanced_logic.rhai"
[body]
raw = ""
type = "json"
[assert]
status = 201
advanced_logic.rhai
// Advanced Rhai pre-request script demonstrating control flows, loops, and error throwing
log("Executing advanced pre-request hook...");
// 1. Error Throwing: Validate that base_url is present
if !vars.contains("base_url") {
throw "Missing required environment variable: base_url";
}
// 2. If/Else condition: Apply dynamic logic based on variables
let role = "user";
if vars.contains("role_to_assign") {
role = vars["role_to_assign"];
}
if role == "admin" {
log("High-privilege role detected. Injecting admin flag.");
headers["X-Admin-Required"] = "true";
} else {
log("Standard role detected: " + role);
headers["X-Admin-Required"] = "false";
}
// 3. Loops and Iteration: Dynamically build a JSON body
log("Building dynamic list of items in request body...");
let items_json = "[";
for i in 0..3 {
if i > 0 {
items_json = items_json + ",";
}
items_json = items_json + `{"item_id": ` + i + `, "name": "Item ` + i + `"}`;
}
items_json = items_json + "]";
// Inject the computed structure into the body
body = `{"username": "admin_user", "role": "` + role + `", "permissions": ` + items_json + `}`;
log("Computed Advanced Body: " + body);
rumour run ./scripting_examples/pre_request/advanced_flow.toml -tv
Output
Running the advanced suite outputs:
[SCRIPT] Executing advanced pre-request hook...
[SCRIPT] High-privilege role detected. Injecting admin flag.
[SCRIPT] Building dynamic list of items in request body...
[SCRIPT] Computed Advanced Body: {"username": "admin_user", "role": "admin", "permissions": [{"item_id": 0, "name": "Item 0"},{"item_id": 1, "name": "Item 1"},{"item_id": 2, "name": "Item 2"}]}
POST http://localhost:4000/api/v2/users
Header: X-Admin-Required: true
URL: http://localhost:4000/api/v2/users
Body (json): {"username": "admin_user", "role": "admin", "permissions": [{"item_id": 0, "name": "Item 0"},{"item_id": 1, "name": "Item 1"},{"item_id": 2, "name": "Item 2"}]}
✓ SUCCESS: /home/bugsfounder/workspace/testing/scripting_examples/pre_request/advanced_flow.toml (1ms)
✓ ./scripting_examples/pre_request/advanced_flow.toml → PASS (1 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1 │
│ Successful: 1 │
│ Failed: 0 │
│ Skipped: 0 │
│ Success Rate: 100.0% │
│ Total Time: 2ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- /home/bugsfounder/workspace/testing/scripting_examples/pre_request/advanced_flow.toml [201] [2ms]
Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.
Understanding the Output
Here is what is happening during the advanced run:
-
Script Validation & Setup:
- The script ensures
base_urlis present invars. - It checks
vars["role_to_assign"]. Since it equals"admin", the script enters theifblock, logs the event, and injects the headerX-Admin-Required: true.
- The script ensures
-
Loop Iteration:
- The
forloop executes 3 times (from index0to2), concatenating individual JSON items to build thepermissionslist ([{"item_id": 0...}, ...]).
- The
-
Request Transmission:
- The
POSTrequest is sent with the calculated header (X-Admin-Required: true) and the dynamic payload constructed by the loop. - The request successfully validates against the
201status assertion.
- The
Script Errors
If your script contains a syntax error or throws a runtime exception, Rumour stops the entire request execution and prints a clear error in the execution report under the failed request:
Reason: Script error: Script error in /absolute/path/to/inject_headers.rhai: Variable not found: undefined_var (line 3, position 1)
The request will not be sent. Fix the script and re-run.
Understanding the Error Output
When a script error occurs:
- Immediate Halt: Rumour stops execution immediately and does not send the HTTP request.
- Error Details: It pinpoints the absolute path of the script, the exact error message (
Variable not found: undefined_var), and the precise line/column number (line 3, position 1) where the problem occurred to help you debug quickly.