본문 바로가기
Data Science

python pydantic이란? typing과 함께 사용법 이해하기

by Lora Baek 2024. 8. 9.
300x250

python의 pydantic 라이브러리를 사용하면 input 데이터 검증을 할 수 있다.

나는 원하는 조건을 지정해서 해당 조건에 맞는 데이터가 들어올 때만 정상적인 응답을 리턴해주고,

그렇지 않다면 오류를 반환하도록 도와주는 라이브러리라는 것으로 이해하고 있다.

 

pydantic은 BaseModel을 상속하는 방식으로 활용하는데,

이 때 BaseModel은 객체를 정의하는 방법을 제공해준다고 생각하면 편할 것 같다.

 

또한 typing 모듈과 함께 사용할 때 큰 효과를 발휘한다.

FastAPI 앱과 함께 pydantic의 예제와 그 필요성을 살펴보자.

 

 

먼저 pydantic을 사용하지 않는다면?

아래와 같이 POST를 보낼 때 타입을 지정해서 main2.py를 작성해보자.

from fastapi import FastAPI

app = FastAPI()

@app.post("/items/")
async def create_item(name: str, phone : int = None):
    return name, phone
uvicorn main2:app --host 0.0.0.0 --port 4000 --reload

4000번 포트를 열고, main2를 실행해주었다.

 

http://0.0.0.0:4000으로 접속해서 name을 "안녕하세요", phone을 01077777777로 보냈을 때 Curl을 보자.

url에 정보들이 다 담겨있고, -d(body)에는 아무 것도 담겨 있지 않다.

url에 정보들이 다 들어있으면 중요한 정보를 담아 요청을 보낼 때 보안 상 문제가 될 수 있으므로, body에 데이터를 담아서 통신하는 것이 좋다.

 

그럼 이제 pydantic을 사용해서 코드를 다시 작성해보자.

BaseModel을 상속받는 Item 클래스를 작성해준다.

 

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    phone : int

@app.post("/items/")
async def create_item(item: Item):
    return item

 

curl을 보면 url이 아니라 body에 내용이 담겨 있다.

우리가 원하는 형식으로 요청이 들어오는지, fastapi 서버가 요청받은 내용을 pydantic을 이용해서 확인하게 된다!

 

형식에 맞지 않는 데이터를 전송하면 아래와 같이 422 에러를 반환하게 된다.

단, 숫자에 ""를 씌워 "0107777"과 같은 text 형태로 넣더라도 자동으로 int로 변환해준다.

 

이제 Field 개념을 추가하고, typing과 결합해보자.

from typing import Optional, Union, List, Any
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str
    phone : Optional[int] = None # phone의 값을 Optional로 지정, 기본값을 None으로 설정. 확실히 None 값이 허용된다면 선택적인지와 관계없이 Optional을 붙여주는 것이 좋다.
    description : Union[int,float] # int, float 중 무엇이 들어오건 상관 없음
    address : str = Field(example='서울특별시 ㅇㅇ구') #str 타입이고, 예시 설명을 추가
    status : List[Any] = Field([], description = '텍스트로 상태를 설명해주세요') # 어떤 타입이든 받을 수 있는 리스트인데 기본 값은 비어있는 list[]
    

@app.post("/items/")
async def create_item(item: Item):
    return item

 

선택적으로 값을 받고 싶다면 Optional을 사용한다.

phone의 값을 Optional로 지정했는데, 기본값을 None으로 설정. 확실히 None 값이 허용된다면 선택적인지와 관계없이 Optional을 붙여주는 것이 좋다. 

 

Union은 지정한 타입 중 하나이면 허용한다는 뜻이다.

int, float 중 무엇이 들어오건 상관 없으나 텍스트를 넣으면 오류를 반환할 것.

 

address에는 Field를 추가해주었다. str 타입이고, 예시 설명을 추가해서 입력 시 참고할 수 있도록 해보았다.

 

status 어떤 타입이든 받을 있는 리스트인데 기본 값은 비어있는 list[]이다.

phone은 선택적인 값이므로 아예 지운다면 null값이 들어가게 된다.

 

docs를 확인해보자. try it out을 누르면 다음과 같이 request body가 보인다.

 

이 값을 수정해서 post 요청을 보내보자.

optional한 값인 phone은 아예 삭제한다면 null값으로 들어가게 된다.

 

 

description으로 적은 내용은 아래의 Schemas에서 확인 가능하다!

 

만일 요청에 맞지 않는 데이터를 보내게 되면?

 

이런 식으로 오류 메세지가 표출된다.

Input should be a valid integer, unable to parse string as an integer",

댓글