python
45 lines · 6 steps
Enforcing a max request body size in FastAPI
A Starlette middleware that rejects oversized request bodies both by declared header and by actual bytes streamed.
Explained by
highlit
1from starlette.middleware.base import BaseHTTPMiddleware
2from starlette.requests import Request
3from starlette.responses import JSONResponse, Response
4from starlette.status import HTTP_413_REQUEST_ENTITY_TOO_LARGE
5
6
7class MaxBodySizeMiddleware(BaseHTTPMiddleware):
8 def __init__(self, app, *, max_bytes: int = 1024 * 1024):
9 super().__init__(app)
10 self.max_bytes = max_bytes
11
12 async def dispatch(self, request: Request, call_next) -> Response:
13 content_length = request.headers.get("content-length")
14 if content_length is not None:
15 try:
16 declared = int(content_length)
17 except ValueError:
18 return self._too_large()
19 if declared > self.max_bytes:
20 return self._too_large()
21
22 received = 0
23 chunks: list[bytes] = []
24 async for chunk in request.stream():
25 received += len(chunk)
26 if received > self.max_bytes:
27 return self._too_large()
28 chunks.append(chunk)
29
30 body = b"".join(chunks)
31
32 async def receive():
33 return {"type": "http.request", "body": body, "more_body": False}
34
35 request._receive = receive
36 return await call_next(request)
37
38 def _too_large(self) -> JSONResponse:
39 return JSONResponse(
40 status_code=HTTP_413_REQUEST_ENTITY_TOO_LARGE,
41 content={
42 "detail": "Request body exceeds the maximum allowed size",
43 "max_bytes": self.max_bytes,
44 },
45 )
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Trusting the Content-Length header alone is unsafe; you must also count the bytes you actually read.
- 2Consuming request.stream() drains it, so you must replace request._receive to let downstream handlers read the body again.
- 3Returning a Response from dispatch short-circuits the request before it ever reaches the route.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
python
import secrets from django.contrib.auth import authenticate, login from django.core.cache import cache
Two-factor login with OTP in Django
two-factor-auth
one-time-passwords
caching
Intermediate
9 steps
go
package middleware import ( "net/http"
Per-plan export limits in Gin middleware
middleware
rate-limiting
authorization
Intermediate
7 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/enforcing-a-max-request-body-size-in-fastapi-explained-python-2ae8/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.