FastAPI

FastApi 사용하면서 기록할 것들

r잡초처럼 2023. 8. 30. 19:36

Embed

만약 Body 에서 Request Body 내부에 Key 로 구분지어서 받고 싶다면 Embed=True 로 설정하면 된다. 다음과 같이 나온다

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    results = {"item_id": item_id, "item": item}
    return results

이렇게 하면 아래와 같이 나온다.

{
  "item": {
    "name": "string",
    "description": "string",
    "price": 0,
    "tax": 0
  }
}

BaseModel로 QueryParam 사용하기

참고 자료
1. https://github.com/tiangolo/fastapi/discussions/6495

2. https://stackoverflow.com/questions/62468402/query-parameters-from-pydantic-model

 

Query parameters from pydantic model

Is there a way to convert a pydantic model to query parameters in fastapi? Some of my endpoints pass parameters via the body, but some others pass them directly in the query. All this endpoints s...

stackoverflow.com

만약 query param의 개수가 많다면 BaseModel로 선언하고, 아래와 같이 사용하면 된다.

class Foo(BaseModel):
	num: int
    char: str


@app.put("/items/{item_id}")
async def get_item(
    query_parm: Foo = Depends(),
):
	...

여기에 Field와 Query를 추가하면 metadata도 추가할 수 있다.

class Foo(BaseModel):
	num: int = Field(
        Query(
            ...,
            description="숫자"          
            example=1,
        ),
    )
    char: str = Field(
        Query(
            ...,
            description="문자"          
            example="hello, world.",
            min_length=1,
        ),
    )

response_model_exclude_unset=True

값이 할당 되지 않은 예를 들면 Key가 없는 건 response 모델에서 뺀다.

class Item(BaseModel):
    name: str
    description: str | None = 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]

response 모델은 Item으로 정의되어 있지만, response를 보면 key 가 없는 foo의 경우엔 보이지 않는다.

{
  "name": "Foo",
  "price": 50.2
}

Response Model  Union

class BaseItem(BaseModel):
    description: str
    type: str


class CarItem(BaseItem):
    type: str = "car"


class PlaneItem(BaseItem):
    type: str = "plane"
    size: int


items = {
    "item1": {"description": "All my friends drive a low rider", "type": "car"},
    "item2": {
        "description": "Music is my aeroplane, it's my aeroplane",
        "type": "plane",
        "size": 5,
    },
}


@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
    return items[item_id]

이런식으로 response_model을 선언하면 schema에선 다음과 같이 보인다.