본문 바로가기
파이썬/FastAPI

[FastAPI] Response Model - 응답을 효과적으로 처리하는 방법

by 책 읽는 개발자_테드 2022. 5. 10.
반응형

· 어떤 path operations 이든지 response_model 매개변수와 함께 응답을 위한 모델을 선언할 수 있다.

ex) @app.get(), @app.post(), @app.put(), @app.put(), @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

 

· response_model은 Pydantic 모델 속성에 대해 선언하는 것과 동일한 타입을 수신하므로, Pydantic 모델이나거 Pydantic 모델의 list일 수 있다. ex) List[Item]

 

· FastAPI는 response_model을 사용하여 다음을 수행한다.

출력 데이터를 모델로 제한한다. 

- 출력 데이터를 해당 타입 선언으로 변환한다.

- 데이터를 검증한다.

- 응답을 위한 JSON 스키마를 OpenAPI path operation에 더한다.

- 자동 문서화 시스템에서 사용된다.

 

· 응답 모델(Response Model)은 함수 리턴 타입 애너테이션 대신 매개변수에서 선언된다. path 함수가 사실상 응답 모델을 반환하는 것이 아니라 딕셔너리, 데이터베이스 객체 또는 다른 모델을 리턴한 다음에 필드 제한과 직렬화를 위해 response_model을 사용하기 때문이다.

 

· plaintext password를 포함하는 UserIn 모델을 선언한다. 그리고 이 모델을 사용하여 입력과 출력을 선언한다. 

 

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

 

· 동일한 모델을 사용하여 입력과 출력을 선언할 수 있다. 하지만, 이렇게 하면 브라우저가 비밀번와 함께 사용자를 생성할 때마다 API는 응답에서 동일한 암호를 반환한다. 이 경우 사용자 자신이 암호를 보내는 것이라 문제가 되지 않을 수 있다. 그러나 다른 path operation에 동일한 모델을 사용하는 경우 사용자의 암호를 모든 클라이언트에 보낼 수 있다.

 

· 위 문제를 해결하기 위해서 평문 암호가 있는 입력 모델과 이것이 없는 출력 모델을 따로 만들 수 있다. reponse_model에 암호를 포함하지 않는 UserOut 모델을 선언하고, 이것을 response_model로 사용한다.

 

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는 Pydantic을 사용하여 출력 모델에 선언되지 않은 모든 데이터를 필터링하여 처리한다.

 

· automatic docs를 보면, 입력 모델과 출력 모델이 모두 자체 JSON 스키마가 있는걸 확인할 수 있다.

 

· 응답 모델은 기본 값을 가질 수 있다.

 

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] = []


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

 

· 실제 값이 저장되지 않는 경우 path operation 데코레이터 매개변수로 response_model_exclude_unset=True를 설정하여 결과에서 생략할 수도 있다.

ex) NoSQL에 많은 optional 속성이 있는 모델이 있을 때, 기본값으로 가득 찬 매우 긴 JSON 응답을 보내고 싶지 않을 수 있다.

 

@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]

 

- 이렇게하면, 기본값은 응받에 포함되지 않고 실제로 설정된 값만 포함된다.

 

· path operation 데코레이터 매개변수로 response_model_includeresponse_model_exclude를 사용하여 응답 모델에서 포함하거나 제외할 요소를 선택할 수 있다.

 

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 Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


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

 

출처

 

https://fastapi.tiangolo.com/tutorial/response-model/

반응형

댓글