A drop-in FastAPI wrapper that adds intentional request slowdowns — for chaos engineering, testing, and mayhem.
Reason this release was yanked:
broken
Project description
A drop-in replacement for FastAPI that adds intentional request slowdowns. One import change. Zero other code changes. Maximum mayhem.
# before 😇
from fastapi import FastAPI
app = FastAPI()
# after 😈
from fastapi_evil import EvilAPI
app = EvilAPI() # requests now take 10 seconds. you're welcome.
Install
pip install fastapi-evil
# or with uv
uv add fastapi-evil
To use the fastapi dev CLI (Uvicorn + hot reload), install with the standard extra:
pip install "fastapi-evil[standard]"
# or with uv
uv add "fastapi-evil[standard]"
Then run your app:
# pip
fastapi dev main.py
# uv
uv run fastapi dev main.py
If you want to use the fastapi dev CLI (Uvicorn + hot reload), install with the standard extra:
pip install "fastapi-evil[standard]"
Why Would Anyone Do This?
- Chaos engineering — stress-test your clients without a service mesh
- Reproduce timeout bugs — "it only happens in prod" → now it happens everywhere
- Test retry logic — make your HTTP clients earn it
- Time-limited degradation — slow things down for exactly one hour, then stop
- Convince your boss the servers are overloaded — we do not endorse this
Quickstart
from fastapi_evil import EvilAPI
app = EvilAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
# Every request now waits 10 seconds before responding.
# uvicorn main:app --reload
Parameters
EvilAPI accepts all standard FastAPI constructor arguments plus:
| Parameter | Type | Default | Description |
|---|---|---|---|
slow_for_millis |
int |
10_000 |
Milliseconds to delay each request (10 seconds) |
slow_for_methods |
list[str] | None |
None |
HTTP methods to slow. None = ALL. |
slow_until |
datetime | None |
None |
Stop slowing after this datetime. None = slow forever. |
Examples
Slow only GET requests by 3 seconds
from fastapi_evil import EvilAPI
app = EvilAPI(
slow_for_millis=3_000,
slow_for_methods=["GET"],
)
Time-limited chaos — slow everything for the next hour, then stop
from datetime import datetime, timedelta, timezone
from fastapi_evil import EvilAPI
app = EvilAPI(
slow_for_millis=5_000,
slow_until=datetime.now(timezone.utc) + timedelta(hours=1),
)
Precise method targeting — slow writes only
from fastapi_evil import EvilAPI
app = EvilAPI(
slow_for_millis=2_000,
slow_for_methods=["POST", "PUT", "PATCH", "DELETE"],
)
Use the named constant for readability
from fastapi_evil import EvilAPI, ALL_METHODS
app = EvilAPI(slow_for_millis=8_000, slow_for_methods=ALL_METHODS)
Pass any standard FastAPI kwargs — they all work
from fastapi_evil import EvilAPI
app = EvilAPI(
title="My Suffering API",
version="6.6.6",
description="This API is evil and slow.",
slow_for_millis=1_000,
)
How It Works
EvilAPI subclasses FastAPI and wires a pure ASGI middleware (SlowMiddleware) that calls asyncio.sleep before dispatching each matched request. It uses a pure ASGI implementation (not Starlette's BaseHTTPMiddleware) to avoid known ContextVar propagation bugs. WebSocket and lifespan scopes are passed through untouched.
Request → SlowMiddleware → check method + slow_until → asyncio.sleep → your routes
slow_until and Timezones
slow_until accepts any Python datetime. Timezone-aware datetimes are recommended:
from datetime import datetime, timezone, timedelta
# Good — explicit UTC
slow_until=datetime.now(timezone.utc) + timedelta(hours=2)
# Also works — but emits a UserWarning (assumed UTC)
slow_until=datetime(2026, 12, 31, 23, 59, 59)
Dev Setup
git clone https://github.com/mohsin/fastapi-evil
cd fastapi-evil
uv sync
uv run pytest
Publishing
uv build
uv publish --token pypi-<your-token>
Get your token at pypi.org/manage/account/token.
License
MIT — do whatever evil you want with it.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_evil-0.1.1.tar.gz.
File metadata
- Download URL: fastapi_evil-0.1.1.tar.gz
- Upload date:
- Size: 1.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4de6c5956482b98396cf79a45ba8b5e99ef0c8f04ae670621806fb104de95b02
|
|
| MD5 |
3bf16d281c894f1cd019f2cdfa89cf68
|
|
| BLAKE2b-256 |
b7ee19149babcb6fc3b6a9b3930cb28dc06346c959e1f5bb764d05920815355d
|
File details
Details for the file fastapi_evil-0.1.1-py3-none-any.whl.
File metadata
- Download URL: fastapi_evil-0.1.1-py3-none-any.whl
- Upload date:
- Size: 6.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84e6103ef9572ff3e4ac8518d6e18d6aad94372ba023a8c0eac736c425bcd59a
|
|
| MD5 |
e6af2e3a315d1847a545ecc714882d66
|
|
| BLAKE2b-256 |
a87a383040ab547132b47fe2a18d485fdb10bd14e68aff7ed99a696a546e22e8
|