Access raw request bytes in FastAPI for webhook verification
Tests FastAPI's Starlette integration and stream semantics. Outline: inject Request and await request.body, but the stream is single-use so JSON parsing later fails and docs are lost. Red flag: suggesting a Pydantic model still works after consuming the body.
What's really being asked
Whether you understand that FastAPI is built on Starlette and that HTTP request bodies are streaming byte streams rather than in-memory buffers that can be read repeatedly. The interviewer wants to see if you know how to drop down to the framework level when automatic JSON parsing is insufficient, and if you grasp the trade-offs around validation, documentation, and stream consumption.
The full answer
First, import Request from starlette.requests and declare it as a parameter in your path operation function. Second, read raw bytes with await request.body inside an async handler. Third, explain that the underlying body is an async stream that can only be consumed once, so calling request.body means FastAPI will not be able to populate a Pydantic model from the same request later in that handler. Fourth, note that using Request directly bypasses FastAPI's automatic request validation, type conversion, and OpenAPI schema generation for the body, so you lose docs and validation unless you rebuild them manually.
The mistakes people make
Claiming you can simply add a Pydantic model parameter alongside the Request parameter in the same endpoint and expect both to work, since the body stream would already be exhausted. Suggesting request.json instead of request.body without acknowledging that request.json also consumes the stream and still skips FastAPI model validation. Proposing to read the body in middleware without explaining how to cache it or attach it to scope for downstream use. Forgetting to mention that direct Request usage removes the request body from the generated OpenAPI documentation.
What usually comes next
How would you validate the webhook signature and still return a parsed Pydantic model? The expected path is to manually parse the bytes with json.loads and instantiate the model yourself, or to use a custom middleware or APIRoute that caches the body before the path operation runs. What happens to OpenAPI documentation when you use Request directly? You must document the expected payload manually or accept that the schema will not show the body structure. How would you handle this for a large file upload instead of a small JSON payload? You might discuss using request.stream to avoid loading everything into memory.
A concrete example
Imagine a Stripe webhook endpoint. You define async def webhook(request: Request), then body = await request.body(). You compute an HMAC signature over body using a secret key and compare it to a header. If valid, you parse the JSON with json.loads(body) and pass it into a Pydantic model manually. If you had instead declared a Pydantic parameter first, FastAPI would have consumed the stream to build the model, leaving you unable to access the exact raw bytes needed for the signature check, since JSON whitespace or key ordering might differ from the original payload.
Interview question
When verifying a webhook signature in FastAPI by awaiting request.body(), why will a Pydantic model parameter declared in the same endpoint fail to populate?
- a.The HTTP body stream can only be consumed once, so reading it exhausts the source before the model parser runs.Correct
- b.request.body() copies the bytes into memory, leaving the original stream available for FastAPI's parser to read again.
- c.FastAPI disables automatic body parsing whenever a Starlette Request parameter is present.
- d.The Pydantic model will populate correctly as long as it is declared before the Request parameter in the function signature.
Why? this is the answer
FastAPI relies on Starlette, where the HTTP body is a single-use async stream; once await request.body() consumes it, no bytes remain for the framework's automatic parser to build the Pydantic model. Option D is tempting because declaration order matters in some dependency systems, but the stream is exhausted regardless of parameter order.
Just read this? Test yourself on what you have been reading.
Read the original → fastapi.tiangolo.com
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on fastapi — each one lists the topics its interview covers.
See open roles