FastAPI 응답 모델은 클라이언트에 반환되는 데이터 구조를 정의하는 데 사용되는 강력한 기능이다.
응답 모델을 정의함으로써 API는 반환되는 데이터의 유효성을 보장하고,
OpenAPI 스키마(문서 자동화)를 생성하여 API 사용자에게 명확한 정보를 제공한다.
즉, 응답 모델을 사용하면 API가 반환하는 데이터의 구조를 명확하게 정의하고,
API 문서를 자동으로 생성하여 사용자에게 제공할 수 있으며,
반환 데이터의 유효성 검사를 자동으로 수행할 수 있다.
FastAPI의 라우팅 연산에서 response_model 매개변수를 사용하여 응답 모델을 지정할 수 있다.
이 매개변수는 라우팅 연산 함수에 의해 반환되는 데이터의 형태를 Pydantic 모델로 정의하게 해준다.
이 모델은 반환된 데이터가 클라이언트로 전송되기 전에 Serialize되는 방식을 결정한다.
Serialize는 데이터를 일련의 비트로 변환하여 파일, 메모리, 네트워크를 통해 저장하거나
전송할 수 있는 형식으로 만드는 과정을 말한다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI() # FastAPI 인스턴스를 생성한다.
class Item(BaseModel):
name: str # 아이템의 이름 필드
description: str = None
price: float
def get_item_from_db(id):
# 간단한 아이템 반환하기
return {
"name": "Simple Item",
"description": "A simple item description",
"price": 30.0,
"dis_price": 20.0
}
@app.get("/")
def read_root():
return {'message':'Hello World!!'}
@app.get("/items/{item_id}", response_model=Item)
def read_item(item_id: int):
# 데이터에이스에서 item_id에 해당하는 아이템을 검색 후 반환
item = get_item_from_db(item_id)
return item
[웹브라우저 테스트]
=> response_model 로 정의된 Item 모델로 시리얼라이즈 한 데이터 dict를 반환
위 코드에서 read_item() 함수는 response_model로 Item을 사용한다.
이는 함수가 Item 인스턴스를 반환하거나 Item 모델로 시리얼라이즈 할 수 있는 데이터(예: dict)를 반환한다는 의미이다.
[response_model]의 장점
● 데이터 검증 : 반환 데이터가 response_model에 정의된 모델의 필드 및 타입과 일치하는지 FastAPI에 의해 자동으로 검증됨
● 문서 자동 생성 : FastAPI는 response_model을 사용하여 API 문서에 정확한 응답 형식을 표시할 수 있다.
● 보안 : response_model은 라우팅 연산이 노출할 데이터를 제한하는 데 사용할 수 있다.
만약 response_model을 지정하지 않으면 FastAPI는 반환된 객체를 그대로 JSON으로 변환하여 클라이언트에 반환한다.
이 경우 모든 데이터가 노출 되며, 문서 자동화 기능을 활용하지 못할 수 있다.
결론적으로 response_model은 필수적이지 않지만 API를 더 안전하고, 명확하며, 사용하기 쉽게 만들어주는 중요한 기능을 한다.
[주요 응답모델]
● 기본 응답 모델 : Pydantic 클래스를 이용해 모델 정의. 가장 일반적인 형태
● Generic 응답 모델 : 제네릭 타입을 활용하여 다양한 타입의 응답을 동일한 엔드포인트에서 다룰 수 있다.
● Union 응답 모델 : 여러 가능한 모델 중 하나가 될 수 있는 경우에 유용하다.
● List 응답 모델 : 리스트 형태의 데이터를 반환할 때 사용한다.
1. 기본 응답 모델
Pydantic의 BaseModel을 상속하여 API 응답으로 사용할 데이터 모델을 정의한다.
FastAPI 경로 연산에서 response_model 매개변수를 이용해 이 모델을 지정하면, 해당 라우팅 연산은 지정된 모델로 응답 데이터를 검증하고 시리얼라이즈한다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI() # FastAPI 인스턴스를 생성한다.
class Item(BaseModel):
name: str # 아이템의 이름 필드
price: float
# `response_model`을 `Item`으로 지정하여 반환할 데이터 구조 정의
@app.get("/item/", response_model=Item)
def get_item():
return {"name": "milk_tea", "price": "4.0"}
위 예제에서 get_item() 함수는 Item 모델을 response_model로 사용하여 API 라우팅 연산을 정의 한다.
[웹 테스트]
2. Generic 응답 모델
Generic 응답 모델은 FastAPI에서 타입 매개변수를 이용하여 유연한 응답 타입을 정의할 수 있게 한다.
이는 다양한 데이터 타입에 대해 재사용 가능한 응답 모델을 만들고자 할 때 유용하다.
# main.py로 작성
from fastapi import FastAPI
from pydantic.generics import GenericModel
from typing import TypeVar, Generic
app = FastAPI() # FastAPI 인스턴스를 생성한다.
# 제네릭 타입 매개변수 T를 선언한다.
T = TypeVar("T")
# GenericModel을 상속받아 제네릭 응답 모델을 생성
# 이 모델은 다양한 타입의 'data' 필드를 포함할 수 있다.
class GenericItem(GenericModel, Generic[T]):
data: T # 'data' 필드의 타입은 제네릭 타입 매개변수 T로 선언된다.
# 라우팅 연산에서 'response_model'을 GenericItem[str]으로 지정하여
# 반환되는 'data'필드가 문자열 타입임을 명시한다.
@app.get("/generic_item/", response_model=GenericItem[str])
async def get_generic_item():
# 응답 모델에 맞춰 'data' 필드에 문자열 값을 반환한다.
return {"data": "generic item"}
=> 위 코드의 GenericItem 클래스는 GenericModel과 Generic[T]를 상속받아 제네릭 타입 T를 사용한다.
이는 GenericItem 모델이 어떠한 타입의 data필드도 가질 수 있음을 의미한다.
여기선 이 모델을 str 타입의 data 필드를 가진 모델로 구체화하여 사용한다.
[웹 테스트]
3. Union 응답 모델
Union 응답 모델은 파이썬의 typing 모듈의 Union 타입을 사용하여 하나의 라우팅 연산에서 여러 다른 모델 중 하나를 반환하도록 한다.
이는 API가 다양한 가능성 중 하나를 선택해서 반환해야 할 때 유용하다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Union
app = FastAPI() # FastAPI 인스턴스를 생성한다.
# 각각의 동물을 나타내는 Pydantic 모델 정의하기
class Cat(BaseModel):
name: str # 고양이 이름 필드
class Dog(BaseModel):
name: str # 강아지 이름 필드
# 라우팅 연산에서 'response_model'을 Union[Cat, Dog]으로 지정하여
# 반환되는 응답이 Cat 또는 Dog 모델 중 하나의 형태를 띠게 한다.
@app.get("/animal/", response_model=Union[Cat, Dog])
async def get_animal(animal: str):
# 쿼리 매개변수로 'animal'을 받아서 그에 맞는 동물 데이터를 반환한다.
if animal == "cat":
return Cat(name="MewMew")
else:
return Dog(name="PPoPi")
위 코드내의 Cat과 Dog 클래스는 각각 고양이와 강아지의 데이터를 모델링 한다. get_animal() 함수는 쿼리 매개변수(animal 값)에 따라 Cat 또는 Dog 인스턴스를 반환한다.
response_model=Union[Cat, Dog]에 의해 반환 되는 데이터가 Cat 또는 Dog 모델 중 하나와 일치하는지 FastAPI에 의해 자동 검증 된다.
[웹 테스트]
4. List 응답 모델
List 응답 모델은 FastAPI에서 리스트 형태의 데이터를 반환할 때 사용한다.
이 모델은 List 타입 힌트와 함께 사용된다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
app = FastAPI() # FastAPI 인스턴스를 생성한다.
# Pydantic 모델을 정의한다. 이 모델은 응답 데이터의 각 항목의 구조를 나타앤다.
class Item(BaseModel):
name: str # 아이템의 이름 필드드
# 라우팅 연산에서 'response_model'을 List[Item]으로 지정하여
# 반환되는 응답이 Item 인스턴스들의 리스트임을 명시한다.
@app.get("/items/", response_model=List[Item])
async def get_items():
# 데이터베이스 또는 다른 데이터 소스로 부터 아이템 리스트를 가져와 반환한다.
return[{"name": "Item 1"}, {"name": "Item 2"}]
위 소스에서 get_items() 함수는 List[Item]을 response_model로 사용하여 반환할 데이터의 구조를 정의한다.
이 구조에 따라 /items/ 경로로 들어오는 GET 요청에 대해 Item 인스턴스의 리스트가 JSON 배열로 반환된다.
[웹 테스트]
[최종 정리]
이처럼, FastAPI의 응답 모델을 적절히 활용하면 다양한 상황에서 유연하게 응답 데이터를 관리하며,
클라이언트에게 일관된 데이터 구조를 제공할 수 있다.
이는 클라이언트가 API의 응답을 예측 가능하고 신뢰성 있게 처리할 수 있도록 도와준다.