TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 웹개발>

[파이썬] FastAPI - 응답 모델

by 기록자_Recordian 2024. 8. 18.
728x90
반응형
시작에 앞서
해당 내용은 <가장 빠른 풀스택을 위한 Flask & FastAPI>, Dave Lee 지음. BJ Public 출판.
내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.

이전 내용
 

[파이썬] FastAPI - Pydantic (2)

시작에 앞서해당 내용은 , Dave Lee 지음. BJ Public 출판.내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.이전 내용 [파이썬] FastAPI - HTTP 메서드, Pydantic시작에

puppy-foot-it.tistory.com


FastAPI 응답 모델

 

FastAPI 응답 모델은 클라이언트에 반환되는 데이터의 구조를 정의하는 데 사용되는 강력한 기능이다.

응답 모델을 정의함으로써 API는 반환되는 데이터의 유효성을 보장하고, OpenAPI 스키마(자동 문서화)를 생성하여 API 사용자에게 명확한 정보를 제공한다.

 

FastAPI의 경로 연산에서 response_model 매개변수를 사용하여 응답 모델을 지정할 수 있다.

이 매개변수는 경로 연산 함수에 의해 반환되는 데이터의 형태를 Pydantic 모델로 정의하게 해준다. 이 모델은 반환된 데이터가 클라이언트로 전송되기 전에 시리얼라이즈되는 방식을 결정한다.

★ 시리얼라이즈(serialize): 데이터를 일련의 비트로 변환하여 파일, 메모리, 네트워크를 통해 저장하거나 전송할 수 있는 형식으로 만드는 과정.

from fastapi import FastAPI
from pydantic import BaseModel

app = 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": 50.0,
        "dis_price": 45.0
    }
    
@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

▶ read_item() 함수는 response_model로 Item을 사용한다. 이는 함수가 Item 인스턴스를 반환하거나 Item 모델로 시리얼라이즈할 수 있는 데이터(예.dict)를 반환한다는 의미이다.

 

[response_model의 장점]

  • 데이터 검증: 반환되는 데이터가 response_model에 정의된 모델의 필드 및 타입과 일치하는지 FastAPI에 의해 자동으로 검증된다.
  • 자동 문서 생성: FastAPI는 response_model을 사용하여 API 문서에 정확한 응답 형식을 표시한다. 이는 API 사용자가 기대할 수 있는 응답의 구조를 이해하는 데 도움이 된다.
  • 보안: response_model은 경로 연산이 노출할 데이터를 제한하는 데 사용할 수 있다. (예. 모델에서 반환하지 않아야 하는 내부 정보 숨김)

response_model을 지정하지 않으면 FastAPI는 반환된 객체를 그대로 JSON으로 변환하여 클라이언트에 반환한다. 이 경우 모든 데이터가 노출될 수 있으며, 자동 문서화 기능을 온전히 활용하지 못할 수도 있다.

 

[주요 응답 모델의 종류]

  • 기본 응답 모델: 가장 일반적인 형태. Pydantic 클래스를 이용해 모델을 정의할 수 있다.
  • Generic 응답 모델: 제네릭 타입을 활용하여 다양한 타입의 응답을 동일한 엔드포인트에서 다룰 수 있다.
  • Union 응답 모델: 여러 가능한 모델 중 하나가 될 수 있는 경우에 유용하다.
  • List 응답 모델: 리스트 형태의 데이터를 반환활 때 사용한다.

◆ 기본 응답 모델

Pydantic의 BaseModel을 상속하여 API 응답으로 사용할 데이터 모델을 정의한다.

FastAPI 경로 연산에서 response_model 매개변수를 이용해 이 모델을 지정하면, 해당 경로 연산은 지정된 모델에 따라 응답 데이터를 검증하고 시리얼라이즈 한다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# Pydantic 모델 정의. (응답 데이터의 구조 나타냄)
class Item(BaseModel):
    name: str # 아이템의 이름 필드
    price: float # 아이템의 가격 필드
    
# FastAPI 경로 연산 정의. 이 연산은 GET 요청을 처리하고
# 'response_model'을 'Item'으로 지정하여 반환할 데이터의 구조를 정의
@app.get("/item/", response_model=Item)
def get_item():
    # 데이터베이스나 다른 데이터 소스에서 아이템을 가져와 반환
    # 예시를 위해 고정된 값 반환
    return {"name": "milk", "price": 3.5}

 

curl 명령어

curl -X GET "http://127.0.0.1:8000/item/"

▶ GET 메서드를 사용하여 /item/ 엔드포인트에 요청을 보낸다.


◆ Generic 응답 모델

Generic 응답 모델은 FastAPI에서 타입 매개변수를 이용하여 유연한 응답 타입을 정의한다. 이는 다양한 데이터 타입에 대해 재사용 가능한 응답 모델을 만들고자할 때 유용하다.

from typing import TypeVar, Generic
from fastapi import FastAPI
from pydantic.generics import GenericModel

app = 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"}

 

curl 명령어

curl -X GET "http://127.0.0.1:8000/generic_item/"

▶ GET 메서드를 사용하여 /generic_item/ 엔드포인트에 요청을 보내고, 서버는 GenericItem[str] 모델에 정의된 대로 문자열 타입의 data 필드글 갖는 JSON 응답을 반환한다.

응답은 {"data": "generic_item"} 처럼 data 필드에 "generic_item" 문자열 값을 포함하는 JSON 객체이다.


◆ Union 응답 모델

Union 응답 모델은 파이썬의 typing 모듈에 있는 Union 타입을 사용하여 하나의 경로 연산에서 여러 다른 모델 중 하나를 반환할 수 있도록 한다. 이는 API가 다양한 가능성 중 하나를 선택해서 반환해야 할 때 유용하다.

Union은 타입 힌트로 사용되며, 여기에 지정된 모델 중 하나가 응답 데이터로 사용될 수 있음을 나타낸다.

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

app = 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="Whiskers")
    else:
    	return Dog(name="Fido")

 

curl 명령어

- 고양이 데이터 요청

curl -X GET "http://127.0.0.1:8000/animal/?animal=cat"

- 강아지 데이터 요청

curl -X GET "http://127.0.0.1:8000/animal/?animal=dog"

/animal/ 엔드포인트로 GET 요청을 보내고, 쿼리 매개변수 animal의 값에 다라 서버는 Cat 또는 Dog 모델에 정의된 형태의 JSON 응답을 반환한다. 응답은 쿼리 매개변수 animal의 값이 "cat" 인 경우 {"name": "Whiskers"}, "dog"인 경우 {"name": "Fido"}처럼 해당 동물 이름을 포함하는 JSON 객체이다.

이는 Union[Cat, Dog] 응답 모델에 의해 정의된 데이터 구조에 따라 반환된 것이다.


◆ List 응답 모델

List 응답 모델은 FastAPI 리스트 형태의 데이터를 반환할 때 사용한다. 이 모델은 List 타입 힌트와 함께 사용되며, 반환되는 데이터가 리스트의 각 항목이 특정 모델을 준수하는지를 검증한다.

이를 통해 API 사용자는 반환된 데이터가 일정한 구조를 가지는 배열임을 기대할 수 있다.

from typing import List
from fastapi import FastAPI
from pydantic import BaseModel

app = 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"}]

 

curl 명령어

curl -X GET "http://127.0.0.1:8000/items/"

▶ GET 메서드를 사용하여 /items/ 엔드포인트에 요청을 보내고, 서버는 List[Item] 모델에 정의된 대로 Item 객체의 리스트를 갖는 JSON 응답을 반환한다. 응답은 Item 모델의 구조에 맞춰진 [{"name": "Item 1"}, {"name": "Item 2"}]와 같은 JSON 데이터 배열이다.

이는 FastAPI에서 response_model 을 통해 정의된 리스트 응답 모델의 구조에 따라 반환된 데이터이다.


def vs async def

 

Python을 사용하다 보면 함수와 비동기 함수에 대해 많이 들어보셨을 것이다. 특히, def와 async def의 차이점은 Python 개발자라면 꼭 알아야 하는 중요한 개념 중 하나이다.

 

def와 async def의 차이는 동기와 비동기 실행 방식의 차이이다. 동기 함수는 하나의 작업이 완료될 때까지 다른 작업을 멈추게 되지만, 비동기 함수는 여러 작업을 동시에 처리할 수 있다. 따라서, 작업의 성격에 따라 적절한 함수를 선택하는 것이 중요하다.

출처: https://velog.io/@heyggun/python-async-def

1. def란 무엇인가?

def는 Python에서 함수를 정의할 때 사용하는 키워드이다. 일반적으로 함수는 입력 값을 받아 특정 작업을 수행한 후 결과를 반환하는 코드 블록을 의미한다. 예를 들어, 다음과 같은 코드를 통해 간단한 함수를 정의할 수 있다.

def greet(name):
    return f"Hello, {name}!"
 
 

위 함수는 name이라는 매개변수를 받아서 "Hello, name!"이라는 문자열을 반환한다. 이 함수는 호출되면 바로 실행되고, 작업이 끝날 때까지 프로그램의 흐름을 잠시 멈춘다. 이와 같은 함수를 동기 함수라고 한다.

2. async def란 무엇인가?

async def는 Python에서 비동기 함수를 정의할 때 사용하는 키워드이다. 비동기 함수는 작업이 완료될 때까지 기다리지 않고, 다른 작업을 동시에 수행할 수 있는 함수이다. 예를 들어, 다음과 같은 비동기 함수를 정의할 수 있다.

import asyncio

async def greet(name):
    await asyncio.sleep(1)
    return f"Hello, {name}!"
 

위 함수는 await 키워드와 함께 asyncio.sleep(1)을 사용하여 1초 동안 대기한 후 결과를 반환한다. 비동기 함수는 await 키워드를 사용해 다른 비동기 작업이 완료될 때까지 기다릴 수 있다. 이러한 기능 덕분에, 비동기 함수는 I/O 작업(예: 파일 읽기/쓰기, 네트워크 요청 등)과 같이 시간이 오래 걸리는 작업에 적합하다.

3. def와 async def의 차이점

특징 def async def
실행 방식 동기적 실행 (완료될 때까지 대기) 비동기적 실행 (다른 작업과 병렬 수행)
반환 값 일반적인 값 (예: int, str 등) coroutine 객체를 반환
사용 상황 일반적인 작업에 적합 I/O 바운드 작업에 적합
키워드 return await, return

출처: https://velog.io/@heyggun/python-async-def

4. 언제 async def를 사용해야 할까?

비동기 함수는 주로 다음과 같은 상황에서 유용하다.

  • 네트워크 요청: 예를 들어, 웹 서버에서 여러 클라이언트의 요청을 동시에 처리해야 할 때 비동기 함수는 매우 효과적이다.
  • 파일 입출력: 대용량 파일을 처리할 때 비동기 함수를 사용하면, 파일을 읽거나 쓰는 동안 다른 작업을 수행할 수 있다.
  • 데이터베이스 작업: 비동기 함수는 데이터베이스에서 데이터를 가져오거나 업데이트할 때도 유용하게 사용할 수 있다.

다음 내용

 

[파이썬] FastAPI - 응답 클래스

시작에 앞서해당 내용은 , Dave Lee 지음. BJ Public 출판.내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.이전 내용 [파이썬] FastAPI - 응답 모델시작에 앞서해

puppy-foot-it.tistory.com

 

728x90
반응형