HTTP Client (ctx.http)
The ctx.http object is a pre-configured HTTP client provided to every test for making API requests.
Purpose
To provide a robust, ergonomic way to interact with HTTP APIs while automatically capturing traces and metrics for the Glubean platform.
Design Rationale
Under the hood, ctx.http is a wrapper around the popular ky library, which is a lightweight and elegant fetch wrapper.
Why wrap it instead of just letting you use fetch or ky directly?
- Automatic Tracing: Every request sent through
ctx.httpautomatically generates an API trace (ctx.trace()) with the URL, method, status code, and duration. - Automatic Metrics: Every request emits an
http_duration_msmetric (ctx.metric()) tagged with the method and path, allowing you to track endpoint performance over time in the dashboard. - Ergonomics: It provides built-in support for JSON body parsing, retries, and request/response schema validation.
Scenarios
Basic Requests
The most common scenario is hitting an endpoint and parsing the JSON response.
export const getUser = test("get-user", async (ctx) => {
const baseUrl = ctx.vars.require("BASE_URL");
// Method shortcuts (get, post, put, delete, etc.)
const users = await ctx.http.get(`${baseUrl}/users`).json();
// POST with a JSON payload
const created = await ctx.http.post(`${baseUrl}/users`, {
json: { name: "test" }
}).json();
});Scoped Clients
If your test makes multiple requests to the same base URL with the same headers (e.g., an Authorization header), you can create a locally scoped client using .extend().
export const userFlow = test("user-flow", async (ctx) => {
// Create a customized instance of the HTTP client
const api = ctx.http.extend({
prefixUrl: ctx.vars.require("BASE_URL"),
headers: { Authorization: `Bearer ${ctx.secrets.require("TOKEN")}` }
});
// Now you can just use relative paths
const user = await api.get("users/1").json();
const settings = await api.get("users/1/settings").json();
});Retries and Resilience
When testing against staging or flakey environments, you can configure automatic retries for transient errors (like 502s or 503s).
const res = await ctx.http.get("https://api.flaky.com/status", {
retry: {
limit: 3,
statusCodes: [429, 502, 503, 504]
}
});Inline Schema Validation
If you are using a schema library (like Zod 4, Valibot, or ArkType), ctx.http can automatically validate the request body before it is sent, or the response body after it is received.
import { z } from "zod"; // Zod 4
// import * as v from "valibot"; // Valibot
const UserSchema = z.object({ id: z.number(), name: z.string() });
// const UserSchema = v.object({ id: v.number(), name: v.string() });
const res = await ctx.http.post(`${baseUrl}/users`, {
json: { name: "Alice" },
schema: {
response: UserSchema, // Automatically validates the response against UserSchema
},
});