8 changed files with 158 additions and 0 deletions
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 87 KiB |
@ -0,0 +1,84 @@ |
|||
You can declare the model used for the response with the parameter `response_model` in any of the endpoint creation methods: |
|||
|
|||
* `@app.get()` |
|||
* `@app.post()` |
|||
* `@app.put()` |
|||
* `@app.delete()` |
|||
* etc. |
|||
|
|||
```Python hl_lines="17" |
|||
{!./tutorial/src/response-model/tutorial001.py!} |
|||
``` |
|||
|
|||
!!! note |
|||
Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc), not of your endpoint function like all the parameters and body. |
|||
|
|||
It receives a standard Pydantic model and will: |
|||
|
|||
* Convert the output data to the type declarations of the model |
|||
* Validate the data |
|||
* Add a JSON Schema for the response, in the OpenAPI endpoint |
|||
* Will be used by the automatic documentation systems |
|||
|
|||
But most importantly: |
|||
|
|||
* Will limit the output data to that of the model. We'll see how that's important below. |
|||
|
|||
## Return the same input data |
|||
|
|||
Here we are declaring a `UserIn` model, it will contain a plaintext password: |
|||
|
|||
```Python hl_lines="8 10" |
|||
{!./tutorial/src/response-model/tutorial002.py!} |
|||
``` |
|||
|
|||
And we are using this model to declare our input and the same model to declare our output: |
|||
|
|||
```Python hl_lines="16 17" |
|||
{!./tutorial/src/response-model/tutorial002.py!} |
|||
``` |
|||
|
|||
Now, whenever a browser is creating a user with a password, the API will return the same password in the response. |
|||
|
|||
In this case, it might not be a problem, becase the user himself is sending the password. |
|||
|
|||
But if we use sthe same model for another endpoint, we could be sending the passwords of our users to every client. |
|||
|
|||
!!! danger |
|||
Never send the plain password of a user in a response. |
|||
|
|||
## Add an output model |
|||
|
|||
We can instead create an input model with the plaintext password and an output model without it: |
|||
|
|||
```Python hl_lines="8 10 15" |
|||
{!./tutorial/src/response-model/tutorial003.py!} |
|||
``` |
|||
|
|||
Here, even though our endpoint function is returning the same input user that contains the password: |
|||
|
|||
```Python hl_lines="23" |
|||
{!./tutorial/src/response-model/tutorial003.py!} |
|||
``` |
|||
|
|||
...we declared the `response_model` to be our model `UserOut`, that doesn't include the password: |
|||
|
|||
```Python hl_lines="21" |
|||
{!./tutorial/src/response-model/tutorial003.py!} |
|||
``` |
|||
|
|||
So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic). |
|||
|
|||
## See it in the docs |
|||
|
|||
When you see the automatic docs, you can check that the input model and output model will both have their own JSON Schema: |
|||
|
|||
<img src="/img/tutorial/response-model/image01.png"> |
|||
|
|||
And both models will be used for the interactive API documentation: |
|||
|
|||
<img src="/img/tutorial/response-model/image02.png"> |
|||
|
|||
## Recap |
|||
|
|||
Use the endpoint decorator's parameter `response_model` to define response models and especially to ensure private data is filtered out. |
@ -0,0 +1,19 @@ |
|||
from typing import Set |
|||
|
|||
from fastapi import FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
name: str |
|||
description: str = None |
|||
price: float |
|||
tax: float = None |
|||
tags: Set[str] = [] |
|||
|
|||
|
|||
@app.post("/items/", response_model=Item) |
|||
async def create_item(*, item: Item): |
|||
return item |
@ -0,0 +1,18 @@ |
|||
from fastapi import FastAPI |
|||
from pydantic import BaseModel |
|||
from pydantic.types import EmailStr |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class UserIn(BaseModel): |
|||
username: str |
|||
password: str |
|||
email: EmailStr |
|||
full_name: str = None |
|||
|
|||
|
|||
# Don't do this in production! |
|||
@app.post("/user/", response_model=UserIn) |
|||
async def create_user(*, user: UserIn): |
|||
return user |
@ -0,0 +1,23 @@ |
|||
from fastapi import FastAPI |
|||
from pydantic import BaseModel |
|||
from pydantic.types import EmailStr |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class UserIn(BaseModel): |
|||
username: str |
|||
password: str |
|||
email: EmailStr |
|||
full_name: str = None |
|||
|
|||
|
|||
class UserOut(BaseModel): |
|||
username: str |
|||
email: EmailStr |
|||
full_name: str = None |
|||
|
|||
|
|||
@app.post("/user/", response_model=UserOut) |
|||
async def create_user(*, user: UserIn): |
|||
return user |
Loading…
Reference in new issue