First protected app / Step 4 of 6

Verify a rate limit

Source and package versions

One AIWAF repository. Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/. Source and canonical README. Versions shown describe the source checkout; package releases are independent. Current Python/Node source targets are aiwaf 1.1.8 (Python) and aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.

A successful response tells you the handler ran. To verify enforcement, also cross the configured boundary and inspect the response AIWAF returns before the handler.

1. Start with a fresh counter

Stop the server with Ctrl+C and start it again:

python -m flask --app app:app run --port 5000

The tutorial uses a process-local rate cache, so restarting clears its counters. Keep one development server running and send requests from one client. A production shared cache has a different lifetime.

2. Send four requests

Create a file named verify.py beside app.py with the code below. It uses Python's standard library, so it works without curl and does not need browser headers for the tutorial's selected checks.

verify.py

"""Run against a fresh tutorial server on port 5000."""

from urllib.error import HTTPError
from urllib.request import urlopen

for number in range(1, 5):
    try:
        with urlopen("http://127.0.0.1:5000/api/message") as response:
            print(number, response.status, response.read().decode().strip())
    except HTTPError as response:
        print(number, response.code, response.read().decode().strip())

with urlopen("http://127.0.0.1:5000/health") as response:
    print("health", response.status, response.read().decode().strip())
python verify.py

For a fresh counter, the statuses should be:

1 200 {"message":"Hello from a protected route"}
2 200 {"message":"Hello from a protected route"}
3 200 {"message":"Hello from a protected route"}
4 429 {"error":"too_many_requests"}

Whitespace in JSON may differ. The fourth request is throttled; it does not execute the message handler. This is a rate-limit response, not an anomaly-model prediction or a permanent blocklist entry.

3. Check the exempt route

python -c "from urllib.request import urlopen; r=urlopen('http://127.0.0.1:5000/health'); print(r.status, r.read().decode())"
200 {"ok":true}

The health handler remains reachable even while the message route is throttled. Wait for the 60-second window to expire, or restart this local teaching app, before repeating the message test.

If your result differs

  • First request is already 429: earlier requests used the same bucket; wait for the window or restart the local app.
  • Every request returns 200: verify middleware selection, the loaded app file, the path, explicit route overrides, manifest-inferred budgets, and exemptions. Another running server may be answering on port 5000.
  • You see 403: this tutorial does not select header/keyword checks. Check for different configuration, persisted blocks, or an upstream WAF.
  • Connection refused: check that the first terminal is still running and the port matches.
Checkpoint You have observed both a permitted handler response and an enforced rate boundary.