Skip to main content

A drop-in FastAPI wrapper that adds intentional request slowdowns — for chaos engineering, testing, and mayhem.

Reason this release was yanked:

broken

Project description

  ███████╗ █████╗ ███████╗████████╗ █████╗ ██████╗ ██╗      ███████╗██╗   ██╗██╗██╗
  ██╔════╝██╔══██╗██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██║      ██╔════╝██║   ██║██║██║
  █████╗  ███████║███████╗   ██║   ███████║██████╔╝██║█████╗█████╗  ██║   ██║██║██║
  ██╔══╝  ██╔══██║╚════██║   ██║   ██╔══██║██╔═══╝ ██║╚════╝██╔══╝  ╚██╗ ██╔╝██║██║
  ███████╗██║  ██║███████║   ██║   ██║  ██║██║     ██║      ███████╗ ╚████╔╝ ██║███████╗
  ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝      ╚══════╝  ╚═══╝  ╚═╝╚══════╝

😈 Your FastAPI. Now with more suffering. 😈

PyPI version Python License: MIT Tests


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

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 overloadedwe 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_evil-0.1.0.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_evil-0.1.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_evil-0.1.0.tar.gz.

File metadata

  • Download URL: fastapi_evil-0.1.0.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

Hashes for fastapi_evil-0.1.0.tar.gz
Algorithm Hash digest
SHA256 22b0fe8c970f7f1b64babe1188682455c3106467c99e3265370d04ea50efe1bb
MD5 4f9356ad3d5f9a9632103e2061681363
BLAKE2b-256 b0a3d5acbc3b8f633808185a06c8b5bffdbd71abbb5e3a564c53166fc37ed88d

See more details on using hashes here.

File details

Details for the file fastapi_evil-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_evil-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.9 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

Hashes for fastapi_evil-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fdf0107e28777ab9c2ca4f63feb51b57cf97206bd79653a48b17e47f439727fd
MD5 0e831ab80ff5499fc53e20775cd6eefb
BLAKE2b-256 a96202227c2080ec7464923ec65f40db82ec38db3f15e3089b3a1421ddd91bc2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page