API Load Testing
Stress-test a REST API with diverse, realistic request payloads at maximum throughput using sample mode.
Build a generator that fires a burst of diverse API requests at a target endpoint as fast as possible. Use it to benchmark throughput, uncover race conditions, and validate rate limiters — all without writing test scripts.
What you'll build
The generator uses:
- static input — produces a burst of N timestamps instantly.
- Sample mode (
--live-mode false) — releases all timestamps without waiting for the clock. - chance picking mode — weighted mix of request types (GET, POST, PUT, DELETE).
- HTTP output — sends each event as a request to the target API.
- Batch tuning — controls how many requests are in flight at once.
Prerequisites
- Eventum installed
- A target API endpoint to test (this tutorial uses a placeholder URL — replace it with your own)
Only load-test APIs you own or have explicit permission to test. Sending high-volume traffic to third-party services may violate their terms of service.
Project structure
Build it
Create the project directory
mkdir -p load-test/templates
cd load-testWrite request templates
Each template produces a JSON request body. The HTTP output sends it as a POST to the target endpoint. The template includes the HTTP method and path so the API can route accordingly (adjust the format to match your API's expectations).
GET users — list endpoint, no body needed.
{
"method": "GET",
"path": "/api/v1/users",
"params": {
"page": {{ module.rand.number.integer(1, 100) }},
"limit": {{ module.rand.choice([10, 25, 50]) }}
}
}Create user — POST with a realistic payload.
{
"method": "POST",
"path": "/api/v1/users",
"body": {
"name": "{{ module.faker.locale.en.name() }}",
"email": "{{ module.faker.locale.en.email() }}",
"role": "{{ module.rand.weighted_choice(["viewer", "editor", "admin"], [0.6, 0.3, 0.1]) }}",
"department": "{{ module.rand.choice(["engineering", "marketing", "sales", "support", "hr"]) }}"
}
}Update user — PUT with partial changes.
{
"method": "PUT",
"path": "/api/v1/users/{{ module.rand.number.integer(1, 10000) }}",
"body": {
"name": "{{ module.faker.locale.en.name() }}",
"role": "{{ module.rand.choice(["viewer", "editor", "admin"]) }}"
}
}Delete user — DELETE by ID.
{
"method": "DELETE",
"path": "/api/v1/users/{{ module.rand.number.integer(1, 10000) }}"
}Configure the generator
The static input generates 5,000 timestamps at once. The chance mode distributes requests across the four types with a realistic CRUD mix.
input:
- static:
count: 5000
event:
template:
mode: chance
templates:
- get-users:
template: templates/get-users.jinja
chance: 0.50
- create-user:
template: templates/create-user.jinja
chance: 0.25
- update-user:
template: templates/update-user.jinja
chance: 0.15
- delete-user:
template: templates/delete-user.jinja
chance: 0.10
output:
- http:
url: "http://localhost:8080/api/v1/batch"
method: POST
success_code: 200
headers:
Content-Type: "application/json"
Authorization: "Bearer test-token"
formatter:
format: json-batchKey settings:
- static count: 5000 — the total number of requests to generate.
- chance distribution — 50% reads, 25% creates, 15% updates, 10% deletes — mimics a typical web application workload.
- json-batch formatter — groups events into a JSON array per batch, reducing HTTP round-trips.
Run it
Use eventum generate in sample mode with tuned batch settings:
eventum generate \
--path generator.yml \
--id load-test \
--live-mode false \
--batch.size 100 \
--max-concurrency 10Flags explained:
| Flag | Effect |
|---|---|
--live-mode false | Releases all 5,000 timestamps instantly — maximum throughput |
--batch.size 100 | Groups 100 events per batch before sending |
--max-concurrency 10 | Up to 10 HTTP requests in flight simultaneously |
The generator fires 5,000 requests grouped into 50 batches of 100, with up to 10 batches in flight at once. Adjust --batch.size and --max-concurrency to find your API's breaking point.
Monitor results
While the test runs (or immediately after), check the metrics:
# If running with eventum run, query the REST API:
curl -s http://localhost:9474/api/v1/instances/load-test/metrics | python -m json.toolKey metrics to watch:
| Metric | What it tells you |
|---|---|
write_ok | Successful API requests |
write_failed | Failed requests (timeouts, 5xx errors) |
format_failed | Events that failed JSON validation before sending |
For eventum generate runs, check the summary printed at exit, or add a stdout output to see events in real time.
Going further
- Ramp-up pattern — replace
staticwith linspace over a 5-minute window in live mode to gradually increase load. - Error injection — add a template that sends intentionally malformed requests (missing required fields, invalid types) to test API error handling.
- Multi-endpoint testing — run several generators in parallel via
startup.yml, each targeting a different API service. - Throughput measurement — pipe
stdoutoutput throughpv -lto count events per second in real time.