Skip to main content

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"
tip

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:

ObjectTypeDescription
varsMap (read/write)All runtime variables in scope for this request
headersMap (read/write)Current request headers (before sending)
paramsMap (read/write)Outgoing query parameters of the request
bodyString (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:

  1. Read the base_url and role_to_assign environment variables.
  2. Generate a custom tracking ID and inject it into the request headers as X-Trace-Id.
  3. Read the original request body, modify it to use a dynamic username and the environment-defined role, and update it.
  4. 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:

  1. 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"}).
  2. HTTP Request Details:

    • Method & URL: A POST request 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-hook and X-Trace-Id: track-123456) are attached.
    • Body: The final payload sent is the modified JSON body containing the updated username and role.
  3. Status Check & Execution Report:

    • The server returns status code 201 (Created).
    • Since our assertion expects status = 201, the request passes (✓ SUCCESS).

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"}`;
note

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:

  1. Validation & Aborting: Checking variable presence and throwing an error to halt the run if preconditions are not met.
  2. If/Else Logic: Checking environment values and conditionally modifying headers.
  3. 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:

  1. Script Validation & Setup:

    • The script ensures base_url is present in vars.
    • It checks vars["role_to_assign"]. Since it equals "admin", the script enters the if block, logs the event, and injects the header X-Admin-Required: true.
  2. Loop Iteration:

    • The for loop executes 3 times (from index 0 to 2), concatenating individual JSON items to build the permissions list ([{"item_id": 0...}, ...]).
  3. Request Transmission:

    • The POST request is sent with the calculated header (X-Admin-Required: true) and the dynamic payload constructed by the loop.
    • The request successfully validates against the 201 status assertion.

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:

  1. Immediate Halt: Rumour stops execution immediately and does not send the HTTP request.
  2. 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.