FastAPI response model

Using the response_model parameter, the response model can be declared in the following path parameters:

  • @app.get()
  • @app.put()
  • @app.post()
  • @app.delete()
from typing import List, Optional
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []
    
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
    return item

Note: response_model is a parameter of the decorator method. Unlike the previous parameters and request body, it is not a parameter of the path operation function.

The type received by response_model is the same as the type that declares the Pydantic model property, which can be a Pydantic model or a list of Pydantic models, for example: List[Item]

returns the same input data

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()

class UserIn(BaseModel):
    username: str
    password: str
    email: EmilStr
    full_name: Optional[str] = None
    
    
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
    return user

Use this model to declare input objects, and use the same model to declare output objects:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
    return user

Now, whenever a user is created with a password in the browser, the API will return the same password in the response china. In this example, since the user himself sends the password, this operation is fine, but if the same model is used in other path operations, the user's password will be sent to each client.

Add output model

Create an output model without a plaintext password relative to an input model with a plaintext password:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

Thus, even if the path manipulation function returns the same input user:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

But because the UserOut model declared in response_model does not contain the password:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

FastAPI filters out all data not declared in the output model.

Response model encoding parameters

The response model supports default values:

from typing import List, Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • description: Optional[str] = None The default value is None
  • tax: float = 10.5 The default value is 10.5
  • The default value of tags: List[str] = [] is an empty list: []

However, if no new value is assigned to a property with a default value, the output will omit the property with a default value.

For example, the model of a NoSQL database often contains many optional attributes. If the attribute with default value is output, the output JSON response will be very long. In this case, the attribute with only default value can be omitted.

 

Posted by PolyPill on Thu, 05 May 2022 14:09:31 +0300