FastAPI 서버개발, 스키마 – 요청, 나머지 요청과 응답을 모두 정의하기

FastAPI는 현대적인 웹 API를 구축하기 위한 매우 효율적인 프레임워크입니다. 이 글에서는 FastAPI를 사용하여 요청과 응답을 정의하는 방법, 그리고 Pydantic을 이용한 스키마 정의 방식을 중점적으로 다룰 것입니다. 이러한 구성 요소들은 API의 신뢰성과 데이터 유효성을 높여줍니다.

1. FastAPI 소개

FastAPI는 Python 기반의 웹 프레임워크로, 빠르고 비동기식 HTTP 서비스 개발을 가능하게 합니다. 이 프레임워크의 가장 큰 장점은 데이터 유효성을 검사할 수 있는 강력한 스키마 정의 기능입니다. FastAPI는 비동기 처리를 기본으로 하며, 이는 성능을 높이고 더욱 효율적인 서버를 구축하는 데 크게 기여합니다.

2. Pydantic: 데이터 유효성 검사의 기본

Pydantic은 Python 데이터 유효성 검사 및 설정 관리를 위한 라이브러리로, FastAPI와 직접적으로 통합되어 사용됩니다. Pydantic의 모델을 활용하면 요청과 응답에서 사용하는 데이터 구조를 쉽게 정의하고, 자동으로 유효성을 검사할 수 있습니다.

2.1 Pydantic 모델 생성

Pydantic 모델을 생성하려면 먼저 BaseModel 클래스를 상속받아야 합니다. 다음은 간단한 Pydantic 모델의 예제입니다.


from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str
    email: str

위의 코드에서 User 클래스는 세 가지 필드를 가진 모델을 정의합니다. 각각의 필드는 데이터 타입을 명시하여 FastAPI가 요청의 유효성을 검사할 수 있도록 해줍니다.

2.2 요청 스키마 정의하기

FastAPI에서 API 엔드포인트를 정의할 때, 요청 바디에 사용될 스키마를 클래스 형태로 정의할 수 있습니다. 예를 들어, 사용자 정보를 생성하는 엔드포인트를 다음과 같이 구현할 수 있습니다.


from fastapi import FastAPI

app = FastAPI()

class UserCreate(BaseModel):
    username: str
    email: str

@app.post("/users/")
async def create_user(user: UserCreate):
    return {"username": user.username, "email": user.email}

위 코드에서 /users/ 엔드포인트는 POST 요청을 처리하며, UserCreate 모델을 요구합니다. 클라이언트가 이 API 호출 시 usernameemail 필드를 포함해야 합니다.

3. 응답 스키마 정의하기

응답 스키마도 Pydantic 모델로 정의할 수 있습니다. 요청 처리 후 클라이언트에 반환할 데이터의 구조를 명확히 함으로써 API 사용자가 예상할 수 있는 응답을 보장할 수 있습니다.

3.1 응답 모델 정의

동일한 모델을 응답으로 사용해도 되지만, 경우에 따라 다른 응답 모델이 필요할 수 있습니다. 따라서 아래와 같이 각각의 요청과 응답에 맞는 모델을 정의하는 것이 좋습니다.


class UserResponse(BaseModel):
    id: int
    username: str
    email: str

@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
    dummy_id = 1  # 실제 데이터베이스 쿼리가 필요한 부분
    return UserResponse(id=dummy_id, username=user.username, email=user.email)

여기서 response_model 매개변수를 통해 FastAPI는 자동으로 응답 JSON을 UserResponse에 맞춰서 반환하고, 그 구조를 문서화합니다.

4. 전체 구현 예제

지금까지의 내용을 종합하여 간단한 FastAPI 애플리케이션을 구현해 보겠습니다. 이 예제는 사용자 정보를 관리하는 API를 포함하고 있습니다.


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

app = FastAPI()

class UserCreate(BaseModel):
    username: str
    email: str

class UserResponse(BaseModel):
    id: int
    username: str
    email: str

users_db = {}

@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
    user_id = len(users_db) + 1
    users_db[user_id] = user
    return UserResponse(id=user_id, username=user.username, email=user.email)

@app.get("/users/", response_model=List[UserResponse])
async def get_users():
    return [UserResponse(id=user_id, username=user.username, email=user.email) for user_id, user in users_db.items()]

위의 코드는 두 개의 엔드포인트를 구현합니다. 하나는 사용자 생성 엔드포인트이고, 다른 하나는 모든 사용자를 조회하는 엔드포인트입니다. 데이터베이스를 사용하지 않고 간단한 파이썬 딕셔너리로 데이터를 관리할 수 있습니다.

5. 데이터 유효성 검사

FastAPI는 Pydantic 모델에 정의된 타입에 따라 자동으로 데이터의 유효성을 검사합니다. 예를 들어, 클라이언트가 잘못된 데이터 타입 또는 필수 필드를 누락하여 요청하면 FastAPI는 422 Unprocessable Entity 오류로 응답합니다.

5.1 유효성 검사와 에러 처리

FastAPI는 유효성 검사 오류를 자동으로 처리하며, 상황에 맞는 오류 메시지를 제공합니다. 이를 통해 사용자에게 좀 더 친절한 API를 제공할 수 있습니다.


{
    "detail": [
        {
            "loc": ["body", "username"],
            "msg": "field required",
            "type": "value_error.missing"
        }
    ]
}

위와 같은 JSON 형식의 에러 메시지는 클라이언트가 어떤 필드를 누락했는지 쉽게 이해할 수 있도록 도와줍니다.

6. 문서화

FastAPI의 장점 중 하나는 Swagger UI와 ReDoc을 자동으로 생성하여 API 문서를 쉽게 확인할 수 있는 기능입니다. 이를 통해 관리자는 API의 사용법을 직관적으로 이해하고, 클라이언트도 API 사용법을 쉽게 파악할 수 있습니다.

서버를 실행한 후, http://127.0.0.1:8000/docs에 접속하면 Swagger UI를 통해 API 문서를 확인할 수 있습니다.

7. 결론

이번 글에서는 FastAPI를 사용하여 스키마를 정의하고, 요청과 응답을 처리하는 방법에 대해 자세히 알아보았습니다. Pydantic 모델을 활용하여 데이터의 유효성을 체크하고, 다양한 API 설계를 통해 안정적이고 효율적인 백엔드를 구축할 수 있습니다.

FastAPI는 생태계가 활발하고, 지속적으로 발전하는 프레임워크로, 모든 Python 개발자에게 유용한 도구가 될 것입니다. 효과적으로 FastAPI를 활용하여 고품질의 웹 서비스 또는 API를 구축해보세요!

이글이 FastAPI를 사용하는 데 도움이 되었길 바랍니다. 추가적인 질문이 있다면 언제든지 댓글로 남겨주세요!