Issue
I cam across the below code which I haven't seen before, which is pretty neat:
@app.post("/posts")
def create_posts(payLoad: dict = Body(...)):
print(payLoad['title'], payLoad['content'])
This is from FastAPI. How does it automatically extract the payload into a dictionary? If I just do create_posts(payLoad)
it doesn't do it automatically. Also, what is the difference between doing Body(...)
and Body()
or Body
? All seem to work exactly the same.
Solution
It's a bit more complicated than I am explaining here, but high level it works like this. There are two phases; app startup and request incoming.
1) App startup
When you start up a new FastAPI application, FastAPI identifies all routes (APIRoute
). Your endpoint will be included as an APIRoute
on the main application. When adding this route to your application the following happens:
- The route has a resolver for dependants (read: parameters), which loops over all parameters of your path operation function (
create_posts
) using inspection of the signature. - Based on the type (
dict
) of the parameter (payLoad
) and it's default value (instance ofBody()
), FastAPI saves this information for that parameter in aDependant
on this APIRoute.
So, the resolving of "what type is parameter x
in this route?" happens on startup and initialization of the application and corresponding APIRoute
s.
2) Request comes in
Then a request comes in:
- Uvicorn calls ASGI app (FastAPI in applications.py)
- FastAPI calls the route (APIRoute in routing.py)
- When the APIRoute is called (it's its own ASGI application) by FastAPI, it will try to resolve all 'dependencies' of the path operation function (create_posts). This is where FastAPI will try and resolve the
payLoad
parameter to the typedict
, based on the inspection it performed earlier and stored asDependant
. - FastAPI performs some logic (you could've given config to
Body()
) to cast the incoming request body to the respective parameters (payLoad
). (this happens in dependencies/ultils.py in the functionrequest_body_to_args
). - It returns the value (now a dict) and inserts that in the path operation function. That path operation function returns a value which is then cast to a
Response
.
Hope this clarifies a bit. It's quite complicated to follow a request around in the code base, but overall it's quite neat to be honest!
EDIT2: I missed one of your questions:
Also, what is the difference between doing Body(...) and Body() or Body ?
Body(...)
and Body()
are the same thing. We used to have pass the ...
but recently a version (i believe it was 0.77) was released that accepted ommitting the placeholder. Upon start of the application, Body()
is called (it's a function) which will return an object (also called Body
). The latter is referenced in the Dependant
that is stored on the route. This allows, for example, for the autogeneration of OpenAPI. The use of Body
(so referencing it as an function object rather than calling the function itself), I haven't seen before and is not intended behavior.
Answered By - JarroVGIT
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.