FastAPI에서의 Pydantic(파이단틱)의 역할은 데이터 검증 및 데이터 직렬화를 매우 쉽게 구현해준다는 점이다.
● 데이터 검증 : 잘못된 데이터 처리를 방지하여 버그 및 다양한 문제들을 예방한다.
● 데이터 직렬화: 서로 다른 시스템끼리 데이터를 쉽게 주고받을 수 있게 만들어 준다.
FastAPI에서 요청 바디로 부터 데이터를 받기 위해 반드시 Pydantic 모델을 사용해야 하는 것은 아니다.
하지만, Pydantic 모델을 사용하는 것을 권장한다.
데이터 요청을 위해 자주 사용하는 HTTP POST 메서드는 데이터를 요청 바디에 넣어 전송하므로,
POST 메서드로 API를 선언하는 경우에는 Pydantic 모델 사용을 고려할 필요가 있다.
1. Pydantic 모델 적용하기
아래의 코드에서 Item 클래스가 Pydantic 모델이다. 이 모델은 name, price, is_offer 라는 세 가지 필드를 가진다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI() # FastAPI 인스턴스를 생성한다.
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
@app.get("/")
def read_root():
return {'message':'Hello World!!'}
@app.post("/items/")
def crate_item(item: Item):
return {"item": item}
코드를 위 처럼 작성 후 curl 명령어로 실행 해보자
]# curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\": \"Bread\", \"price\": 3.5, \"is_offer\": true}"
그러면 item이 아래와 같이 JSON 형태로 출력되는 것을 볼수 있다.
2. Pydantic 기본 문법
1) 변수 타입
- int : 정수
- float : 실수
- bool : True/False
- str : 문자열
- datetime.datetime: 날짜와 시간
- Optional : typing 모듈의 일부로, 필드가 선택적임을 나타낸다. 이는 None 값도 허용한다는 것을 의미한다.
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI() # FastAPI 인스턴스를 생성한다.
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: float = 0.1
@app.get("/")
def read_root():
return {'message':'Hello World!!'}
@app.post("/items/")
async def crate_item(item: Item):
return {"item": item}
위 코드에 대해 다음과 같이 curl 명령을 내보내면 다음과 같이 JSON 응답으로 반환된다.
]# curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\": \"Snowman\", \"price\": 11.5}"
curl 명령으로 POST 요청을 보내면, 요청 바디에 포함된 JSON 데이터는 Item 모델의 인스턴스로 변환된다.
Pydantic은 제공된 필드의 타입을 확인하고, 필드값이 필수인지 아닌지에 대한 유효성 검사를 하고 Item 모델에 대한 객체 생성 및 딕셔너리 변환하여 이를 JSON 응답으로 반환하게 된다.
description은 선택적이므로 null로 표시된다.
만약 description을 요청 바디에 표현하기 위해선 str(문자열) 형으로 넣어야 한다.
2) 필드 제약조건
Field는 Pydantic 모델에서 필드에 추가적인 정보나 제약 조건을 지정할 때 사용하는 함수이다. 주요옵션은 아래와 같다.
- default : 필드의 기본값을 지정한다. 만약 기본값이 없다면 필수 입력 필드가 된다.
- alias : JSON 필드의 이름을 파이썬 변수와 다르게 지정할 때 사용한다.
- title : 스키마에서 볼 수 있는 추가적인 정보로 주로 문서화에 사용된다.
- description : 필드에 대한 설명을 추가한다. 주로 API 문서에서 확인할 수 있다.
- min_length & max_length : 문자열 길이의 최소 & 최대값을 지정한다.
- gt(greater than), lt(less than) : 숫자의 크기 제약을 추가한다.
- regex : 정규 표현식을 통한 패턴 매칭을 할 수 있다.
<예시 코드>
# main.py로 작성
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List
app = FastAPI() # FastAPI 인스턴스를 생성한다.
class Item(BaseModel):
# `name`은 최소 3자, 최대 30자를 가져야 하며 필수 필드이다.
name: str = Field(..., title="Item Name", min_length=3, max_length=30)
# `description`은 선택 필드이며, 최대 300자까지 가능하다.
description: str = Field(None, description="The description of the item", max_length=300)
# `price`는 0보다 커야 하며 필수 필드이다.
price: float = Field(..., gt=0, description="The price must be greater than zero")
# `tag` 필드는 선택적이며, 기본값으로 빈 리스트를 갖는다. JSON에서는 'item-tags'로 나타낸다.
tag: List[str] = Field(default=[], alias="item-tags")
@app.get("/")
def read_root():
return {'message':'Hello World!!'}
@app.post("/items/")
async def crate_item(item: Item):
return {"item": item}
3) Field 테스트하기
● 케이스1 : 정상적인 요청
curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\": \"SpiderMan\", \"price\": 3.14}"
=> 이 요청은 정상적이라 서버로 부터 200OK 응답을 받는다.
name, price 의 필수 필드가 Pydandic 필드 제약 조건에 충족하기 때문이다.
● 케이스2 : name 필드의 길이가 짧은 경우
curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\": \"AB\", \"price\": 3.14}"
=> name 필드의 길이가 Pydantic 모델에서 설정한 min_length 조건을 만족시키지 못했기에 에러 메시지를 반환한다.
● 케이스3 : price 필드가 0보다 작거나 같은 경우
curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\": \"Spiderman\", \"price\": -2}"
=> 이 요청도 Pydandic 모델에서 정의된 gt 조건을 위반하여, 422 Unprocessable Entity 에러를 반환한다.
● 케이스4 : 필수 필드 누락(name)
curl -X POST "http://127.0.0.1:8000/items/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"price\": 11.4}"
=> 이 요청도 Pydandic 모델에서 정의된 name의 필수 조건을 위반하여, 422 Unprocessable Entity 에러를 반환한다.