Skip to content

HTTP and REST load testing

HTTP and REST are the most common protocols you will load-test. Every MaxoPerf engine supports HTTP — Taurus native, JMeter, and k6 each offer a different trade-off between expressiveness, control, and ease of scripting. This page shows the common patterns and how to read HTTP results in MaxoPerf.

Taurus’s built-in HTTP executor handles REST APIs without needing JMeter or k6. It is the fastest way to write a new HTTP load test for MaxoPerf.

execution:
- concurrency: 100
ramp-up: 30s
hold-for: 5m
scenario: api-crud
scenarios:
api-crud:
default-address: https://api.example.com
headers:
Authorization: "Bearer ${TOKEN}" # injected from MaxoPerf secrets at run time
Accept: application/json
requests:
- label: list-products
url: /v1/products
method: GET
assert:
- equals:
subject: http-code
value: '200'
- label: create-order
url: /v1/orders
method: POST
headers:
Content-Type: application/json
body: '{"productId": "widget-01", "qty": 2}'
assert:
- contains:
subject: body
value: '"orderId"'
- label: get-order
url: /v1/orders/${orderId} # extracted from previous response
method: GET
assert:
- equals:
subject: http-code
value: '200'

Taurus supports extracting a value from one response and using it in the next request:

requests:
- label: create-order
url: /v1/orders
method: POST
body: '{"productId": "widget-01"}'
extract-jsonpath:
orderId: $.orderId # extract from response JSON
- label: get-order
url: /v1/orders/${orderId} # use extracted value
method: GET

k6’s http module gives full control over HTTP requests, with response checking and timing:

import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 50 },
{ duration: '3m', target: 50 },
{ duration: '30s', target: 0 },
],
};
export default function () {
// POST with JSON body
const payload = JSON.stringify({ productId: 'widget-01', qty: 2 });
const params = { headers: { 'Content-Type': 'application/json' } };
const createRes = http.post('https://api.example.com/v1/orders', payload, params);
check(createRes, { 'order created': (r) => r.status === 201 });
const orderId = createRes.json('orderId');
// GET with extracted value
const getRes = http.get(`https://api.example.com/v1/orders/${orderId}`);
check(getRes, { 'order found': (r) => r.status === 200 });
}

Configure the Authorization header with a MaxoPerf secret instead of hard-coding the token:

# Taurus YAML
scenarios:
authed-api:
headers:
Authorization: "Bearer ${API_TOKEN}" # set API_TOKEN in Manage test secrets
requests:
- url: /v1/protected-resource
method: GET

See Manage test secrets for how to inject runtime secrets.

For APIs that require a login step to obtain a token:

scenarios:
login-and-call:
requests:
- label: login
url: /v1/auth/login
method: POST
body: '{"email": "${USER_EMAIL}", "password": "${USER_PASSWORD}"}'
headers:
Content-Type: application/json
extract-jsonpath:
access_token: $.token
- label: get-profile
url: /v1/me
method: GET
headers:
Authorization: "Bearer ${access_token}"

After a run, the Overview tab shows the full HTTP result breakdown:

Key metrics to check:

PanelWhat to look for
Throughput chartFlat line during hold-for = stable load. Dips indicate system or runner throttling.
Latency chartp95 rising sharply under load = bottleneck. p50 and p95 diverging = high tail latency.
Error rate panelAny non-2xx responses. Drill into the Log tab for the breakdown by endpoint and status code.
Per-endpoint panelCompare latency across endpoints to find the slow one.

Do:

  • Label every request in your scenario (label: in Taurus, name tag in k6’s http.get) — labels appear in the per-endpoint breakdown in MaxoPerf results.
  • Use extraction and parameterization for flows that span multiple requests.
  • Set realistic think time (sleep() in k6, or think-time: in Taurus) between requests — pure closed-loop tests drive more RPS than real users would.

Don’t:

  • Hard-code secrets (API tokens, passwords) in test files — inject them via MaxoPerf secrets.
  • Test against production systems without authorization from your operations team and a clear communication plan.
  • Ignore 4xx errors in results — a high rate of 400/401/404 responses usually indicates a test scripting problem, not a real load problem.