starlette-middleware-collection
A small collection of Starlette compatible middleware, with FastAPI compatibility and examples.
Included Middleware
SizeLimit: Rejects requests with bodies larger than a configured byte limit.RequestUUID: Adds a per-request UUID torequest.state.id.ResponseUUID: Sets anX-Api-Request-Idresponse header, propagating theRequestUUIDid when present.ResponseTime: Adds anX-Process-Timeresponse header with the request duration in seconds.RequestLogging: Logs one record per request, with a configurable structure and pluggable backend.
Installation
Install from PyPI:
pip install starlette-middleware-collection
Or with uv:
uv add starlette-middleware-collection
SizeLimit
The SizeLimit middleware checks the incoming content-length header and returns 413 Content Too Large when the request body exceeds the configured limit.
- Constructor argument:
limit(bytes) - Environment variable:
MW_REQUEST_BODY_LIMIT - Default:
10 * 1024 * 1024(10 MB)
Basic Usage (SizeLimit)
from fastapi import FastAPI
from starlette_middleware_collection import SizeLimit
app = FastAPI()
app.add_middleware(SizeLimit)
With a Custom Limit
from fastapi import FastAPI
from starlette_middleware_collection import SizeLimit
app = FastAPI()
app.add_middleware(SizeLimit, limit=5 * 1024 * 1024) # 5 MB
Using Environment Variable (SizeLimit)
import os
from fastapi import FastAPI
from starlette_middleware_collection import SizeLimit
os.environ["MW_REQUEST_BODY_LIMIT"] = str(1024 * 1024) # 1 MB
app = FastAPI()
app.add_middleware(SizeLimit)
[!NOTE] The constructor argument takes precedence over the environment variable.
RequestUUID
The RequestUUID middleware sets request.state.id for every request.
- Constructor argument:
uuid_version - Environment variable:
MW_UUID_VERSION - Supported versions:
4,7 - Default:
7
Basic Usage (Default UUIDv7)
from fastapi import FastAPI, Request
from starlette_middleware_collection import RequestUUID
app = FastAPI()
app.add_middleware(RequestUUID)
@app.post("/")
async def read_root(request: Request):
return {"uuid": str(request.state.id)}
With a Custom UUID Version
from fastapi import FastAPI
from starlette_middleware_collection import RequestUUID
app = FastAPI()
app.add_middleware(RequestUUID, uuid_version=4)
Using Environment Variable (RequestUUID)
import os
from fastapi import FastAPI
from starlette_middleware_collection import RequestUUID
os.environ["MW_UUID_VERSION"] = "4"
app = FastAPI()
app.add_middleware(RequestUUID)
[!NOTE] The constructor argument takes precedence over the environment variable.
If an unsupported uuid_version is provided, a ValueError is raised.
ResponseUUID
The ResponseUUID middleware sets a request-id header (X-Api-Request-Id by default) on
every response. When RequestUUID is also installed it propagates the same
request.state.id; otherwise it generates a fresh UUID so the header is always present.
- Constructor arguments:
header_name,uuid_version - Environment variable:
MW_RESPONSE_ID_HEADER(header name) - Default header:
X-Api-Request-Id - Supported versions:
4,7(default7, used only when generating a fresh id)
Basic Usage (ResponseUUID)
from fastapi import FastAPI
from starlette_middleware_collection import ResponseUUID
app = FastAPI()
app.add_middleware(ResponseUUID) # generates a fresh id per response
Paired with RequestUUID
from fastapi import FastAPI
from starlette_middleware_collection import RequestUUID, ResponseUUID
app = FastAPI()
app.add_middleware(ResponseUUID) # reads request.state.id ...
app.add_middleware(RequestUUID) # ... which this sets
With a Custom Header (ResponseUUID)
from fastapi import FastAPI
from starlette_middleware_collection import ResponseUUID
app = FastAPI()
app.add_middleware(ResponseUUID, header_name="X-Trace-Id")
[!NOTE] The constructor argument takes precedence over the environment variable.
ResponseTime
The ResponseTime middleware measures how long each request takes and sets the elapsed
time (in seconds) on a response header (X-Process-Time by default).
- Constructor argument:
header_name - Environment variable:
MW_TIMING_HEADER(header name) - Default header:
X-Process-Time
Basic Usage (ResponseTime)
from fastapi import FastAPI
from starlette_middleware_collection import ResponseTime
app = FastAPI()
app.add_middleware(ResponseTime) # e.g. X-Process-Time: 0.001234
With a Custom Header (ResponseTime)
from fastapi import FastAPI
from starlette_middleware_collection import ResponseTime
app = FastAPI()
app.add_middleware(ResponseTime, header_name="X-Elapsed-Seconds")
[!NOTE] The constructor argument takes precedence over the environment variable.
RequestLogging
The RequestLogging middleware emits one log record per request. By default it logs a
structured dict to a standard-library logger; you can customize the record with a
formatter and route it anywhere with a handler (a sync or async callable — write to a
file, database, queue, etc.). It pairs with RequestUUID: when a request id exists it is
included as request_id.
- Constructor arguments:
logger,level,handler,formatter - Environment variable:
MW_REQUEST_LOG_LEVEL(log level, e.g.20forINFO) - Default logger:
starlette_middleware_collection.request - Default level:
logging.INFO
The default record looks like:
{
"request_id": "019f84...", # or None when RequestUUID is not installed
"method": "POST",
"path": "/upload",
"status_code": 200,
"duration_ms": 12.3,
"client": "127.0.0.1",
}
Basic Usage (RequestLogging)
import logging
from fastapi import FastAPI
from starlette_middleware_collection import RequestLogging
logging.basicConfig(level=logging.INFO)
app = FastAPI()
app.add_middleware(RequestLogging)
Custom Backend (file, database, ...)
from fastapi import FastAPI
from starlette_middleware_collection import RequestLogging
async def to_database(record: dict) -> None:
await db.access_logs.insert(record) # your async backend
app = FastAPI()
app.add_middleware(RequestLogging, handler=to_database)
Custom Record Structure
from fastapi import FastAPI, Request
from starlette.responses import Response
from starlette_middleware_collection import RequestLogging
def formatter(request: Request, response: Response, elapsed: float) -> str:
return f"{request.method} {request.url.path} -> {response.status_code} ({elapsed:.3f}s)"
app = FastAPI()
app.add_middleware(RequestLogging, formatter=formatter)
[!NOTE] A failing
handlernever breaks the request; the error is logged instead.
Combined Example
from fastapi import FastAPI, Request
from starlette_middleware_collection import (
RequestLogging,
RequestUUID,
ResponseTime,
ResponseUUID,
SizeLimit,
)
app = FastAPI()
# Middleware run outermost-first (last added runs first on the way in).
app.add_middleware(RequestLogging)
app.add_middleware(ResponseTime) # X-Process-Time
app.add_middleware(ResponseUUID) # X-Api-Request-Id (propagated below)
app.add_middleware(SizeLimit, limit=2 * 1024 * 1024) # 2 MB
app.add_middleware(RequestUUID, uuid_version=7) # sets request.state.id
@app.post("/upload")
async def upload(request: Request):
return {"request_id": str(request.state.id)}
Changelog
See CHANGELOG.md for a detailed list of changes and version history.
Requirements
Currently supports only Python 3.14 with latest version of Starlette. We plan on supporting older versions of Python and Starlette in the near future.
Contributing
For bugs / feature requests please submit issues. If you would like to contribute to this project, you are welcome to submit a pull request
Warranty / Liability / Official support
This project is being developed independently, we provide the package "as-is" without any implied warranty or liability, usage is your own responsibility
Release files for starlette-middleware-collection 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| starlette_middleware_collection-0.2.0.tar.gz | 6.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| starlette_middleware_collection-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.0 kB
Release files / starlette_middleware_collection-0.2.0.tar.gz
| Download URL | starlette_middleware_collection-0.2.0.tar.gz |
|---|---|
| Size | 6.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4171a4fa95a725c32c4de6f214564b2b7fb1acfb685bc6194051b719cc2ce174
|
|
BLAKE2b-256 checksum How to use checksums |
d671c5cf311f8e3b98ce42f72cb5f33e7c06c3089f9e9b5e213988a5ea7cede0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / starlette_middleware_collection-0.2.0-py3-none-any.whl
| Download URL | starlette_middleware_collection-0.2.0-py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff6e404c398a69e971a12e4fce0a9c7da042e7b0f3543e864e1947eca13f3f3d
|
|
BLAKE2b-256 checksum How to use checksums |
46b93a9591fa3fe385c0684ca362d6f2e5cec0225f880be6623e2e4fa3abd659
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|