Fast API, Response Model (Output 데이터 형식)

Junha Kim·2021년 1월 23일
3

FastAPI

목록 보기
14/16

Fast API에서는 response_model이라는 인자로 손쉽게 데이터를 정형화하여 내보낼 수 있다. response model은 pydantic으로 정의된 모델이나 이를 담는 데이터 형식이 될 수 있다.

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

path operation 부분인 app.post의 인자로 response_model=Item이라고 명시하여 create_item의 return 값이 Item에 정의된 형식에 맞춰서 내보내지게 된다.

만약 Item이 담긴 리스트를 내보내고 싶다면, List[Item]처럼 정의하면 된다.

또한, create_item 함수가 Item 모델에서 선언한 필드나 타입 이외에 더 많은 데이터를 가지고 있더라도, 모델에 선언된 데이터만 내보내지게 된다.

즉, response_models

  • output 데이터를 선언한 타입에 맞게 컨버팅
  • 데이터 유효성 검사
  • JSON 직렬화
  • automatic documenting

의 이점을 가진다.

아래는 유저 모델을 가지고 작성한 예제이다.

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

UserIn 모델은 response body로 들어오며 새로운 유저를 만들기 위한 폼이다. 반면에 UserOut 모델은 생성된 유저에 대한 정보를 다시 클라이언트에게 보내게 되는 모델이다.

자세히 보면, password는 내보내지 않는 것을 볼 수 있다.

위와같이 정의가 되면 /docs에는 아래와 같이 자동으로 documenation이 되게 된다.

Response Model Exclude Unset

만약 response_model로 선택된 모델에 default 값이 선언되어 있는 필드가 있을 때를 생각해보자.

default 값을 api 함수에서 직접 바꾸지 않았을 때, 즉 default 값이 내보내지게 될 때 이러한 바뀌지 않은 값들을 제외시키는 방법이 있다.

그것이 바로 response_model_exclude_unset이다.

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]

위와 같이 response_model_exclude_unset=True로 선언을 하면,

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

이렇게 작성되지 않은 descriptiontax, tags는 제외되어 값이 보내지게 된다.

만약 default value와 똑같은 값을 작성하였으면, fast api는 놀랍게도 새로 씌워진 것으로 판단하고 이를 내보내게 된다.

default value와 똑같은 값이 써졌더라도, 같으면 내보내고 싶지 않을 때는

response_model_exclude_defaults=True 로,

None인 값을 가진 필드를 제외하고 싶으면

response_model_exclude_none=True로 선언하면 된다.

Response Model Include/Exclude

만약 이미 작성한 pydantic 모델에서 특정 필드만을 내보내고 싶거나, 혹은 특정 필드를 제외하고 나머지 필드를 내보내고 싶을 때, response_model_includeresponse_model_exclude으로 선언할 수 있다.

이전까지와는 다르게 str이나 set(listtuple도 가능) 자료형이 들어가야하며, 필드 이름을 넣어야한다.

@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]

@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]

1개의 댓글

comment-user-thumbnail
2023년 4월 25일

팬이에요

답글 달기