HTTP Requests, Mutations & Responses
Guide to configuring HTTP methods, mutation pipelines, response assertions, and payload handling within Budment's two-phase execution architecture.
Budment's HTTP client is tightly integrated into its native Go execution engine, managing persistent connection pools, high-throughput I/O, and automated metric extraction without burdening the JavaScript runtime.
1. HTTP Methods & Target URLs
Initialize request builders using the http factory. These builders must be exported within a scenario pipeline to be executed by the engine.
import { http } from "@budment/sdk";
export default [
http.get("https://api.example.com/v1/users"),
http.post("https://api.example.com/v1/users"),
http.put("https://api.example.com/v1/users/42"),
http.delete("https://api.example.com/v1/users/42"),
];
Target URLs support dynamic expressions using SDK template strings, which are resolved natively by the Go engine during execution:
import { http, env, get } from "@budment/sdk";
export default [
http.get(
`https://${env("API_HOST", "api.example.com")}/users/${get("user_id")}`,
),
];
2. Pre-Request Pipeline
The .before() method is not just a single configuration object; it is a sequential execution pipeline. It accepts variadic arguments (...args), allowing you to chain declarative objects, dynamic JavaScript hooks, and operational nodes (like logs or barriers) in a strict, predictable order.
import { http, log, barrier } from "@budment/sdk";
http.post("https://api.example.com/orders").before(
// 1. JS Hook executes first
(req) => {
req.set({ ts: Date.now() });
},
// 2. Logs output to the console
log("Order request initialized"),
// 3. Workers wait here until the quorum is met before firing the HTTP request
barrier("sync_orders", { quorum: 50 }),
);
Declarative Mutations (Static)
For static configurations, pass a declarative object containing headers and body. The SDK automatically serializes plain JavaScript objects into JSON during the compilation phase.
import { http, env, get, random } from "@budment/sdk";
http.post("https://api.example.com/orders").before({
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${env("AUTH_TOKEN")}`,
},
body: {
order_id: random.uuid(),
quantity: 2,
customer_ref: get("customer_id"),
},
});
Dynamic URLs & Scope Injection
Budment treats target URLs as reactive templates. To mutate paths or query parameters dynamically during execution, embed SDK variables directly into your URL string. The engine instantly evaluates the latest Virtual User scope on demand before dispatching the request.
The HttpRequest Interface
3. Response Pipeline
Similar to .before(), the .after() pipeline sequentially processes response codes, asserts integrity, and extracts state.
Declarative Assertions
Extract JSON fields natively without waking up a JavaScript VM, storing them directly into the Virtual User's memory scope:
http.post("https://api.example.com/auth/login").after({
expect: {
status: 200,
bodyContains: "access_token",
},
extract: {
// Extracts data.token and stores it as 'jwt_token' in VU context
"data.token": "jwt_token",
},
});
Dynamic Response Hooks
Use a JavaScript callback when validations require complex branching. Calling res.json() without arguments parses the entire payload into a JavaScript object:
import { http, set, abort } from "@budment/sdk";
http.get("https://api.example.com/account/profile").after((res, req) => {
// 1. Query specific field using GJSON syntax
const balance = res.json<number>("account.current_balance");
// 2. Or parse the entire response body
const fullProfile = res.json();
if (balance === undefined || balance < 0) {
abort("Invalid account balance detected. Halting iteration.");
}
set("user_profile", fullProfile);
});
The HttpResponse Interface
export interface HttpResponse {
readonly status: number; // HTTP status code (0 for socket/dial errors)
readonly headers: Record<string, string>;
readonly error?: string; // Network timeout or socket error description
// Extracts via GJSON, or parses full body if no selector is provided
json<T = any>(selector?: string): T | undefined;
}
4. File
Uploading binary assets (images, PDFs, archives) requires preserving raw byte streams. Use open(path, 'b') to read the file into an ArrayBuffer, then attach it using req.file():
When req.set() receives fields containing req.file() descriptors, the Go engine automatically formats the payload as multipart/form-data and injects the corresponding Content-Type boundary header.
5. Error & Failure Classifications
Budment strictly distinguishes between business assertion failures, standard HTTP errors, and physical network errors. These define whether a request is flagged as successful (IsSuccess) in the engine's SLA metrics:
| Classification | Trigger Condition | Engine Behavior & Metric Impact |
|---|---|---|
| HTTP Status Error | Server returns Code < 200 or Code >= 400. |
Automatically marks IsSuccess = false. Reflected in standard http_req_failed rates. |
| Assertion Failure | Fails a declarative expect condition. |
Automatically marks IsSuccess = false. |
| Network/I/O Error | Socket timeouts, DNS failures, connection resets. | Returns Status: 0, sets ErrorMessage. Marks IsSuccess = false. |
| Logic Failure | Manual call to fail(reason) in JS hook. |
Logs a FAIL event and continues executing the pipeline. |
| Iteration Abort | Manual call to abort(reason) in JS hook. |
Immediately terminates the JS hook, skips remaining pipeline steps, and restarts the VU iteration. |