FastAPI 서버개발, 스키마 – 응답, 라우터에 정의한 응답에 대한 설명

FastAPI는 현대 웹 API를 간편하게 개발할 수 있는 고속 웹 프레임워크로, Python으로 작성되었습니다. 요즘 많은 개발자들이 Flask나 Django 대신 FastAPI를 선택하는 이유는 빠르게 개발할 수 있는 장점과 다양한 기능을 제공하기 때문입니다. 본 강좌에서는 FastAPI를 이용한 서버 개발 과정에서 응답 스키마, 그리고 라우터에 정의한 응답에 대해 깊이 있게 알아보겠습니다.

1. FastAPI 소개

FastAPI는 다음과 같은 장점을 가지고 있습니다:

  • 신속하게 API 개발이 가능하다.
  • 데이터 검증을 자동으로 수행하며 인텔리센스 지원이 뛰어나다.
  • 비동기 프로그래밍을 지원하여 높은 성능을 발휘한다.
  • OpenAPI 및 JSON Schema를 자동으로 생성한다.

2. FastAPI의 응답 스키마

FastAPI는 Pydantic을 사용하여 데이터 검증 및 데이터 직렬화를 수행합니다. 이를 통해 API의 입력 및 출력 데이터의 구조를 간편하게 정의할 수 있습니다. 응답 스키마를 정의하기 위해서는 Pydantic 모델을 생성하고, 이를 FastAPI의 경로 함수의 응답 타입으로 설정하면 됩니다.

2.1 Pydantic 모델 정의

Pydantic 모델을 정의하기 위해서는 클래스를 만들어야 합니다. 아래의 예시는 사용자의 정보를 표현하기 위한 Pydantic 모델입니다:


from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str
    email: str
    full_name: str = None  # 선택적인 필드

위의 예에서 User 클래스는 FastAPI에서 사용할 응답 스키마를 정의합니다. 각 필드는 해당 데이터 타입을 지정하며, 선택적 필드는 기본값을 None으로 설정합니다.

2.2 경로 함수에서 응답 스키마 사용하기

정의된 Pydantic 모델을 FastAPI의 경로 함수의 반환 타입으로 사용하여, API의 응답 데이터 타입을 명확하게 나타낼 수 있습니다. 예를 들어:


from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}", response_model=User)
async def read_user(user_id: int):
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 코드에서 response_model=User 인자를 통해 FastAPI는 이 경로에서 반환되는 데이터가 User 모델에 맞는지 검증합니다. 만약 반환되는 데이터가 모델과 일치하지 않는 경우, FastAPI는 자동으로 오류 응답을 생성합니다.

3. 라우터에 정의한 응답

FastAPI에서는 경로를 정의하기 위해 라우터를 사용할 수 있습니다. 이는 코드의 구조를 개선하고, 여러 경로를 그룹화하여 관리하기 쉽게 합니다. 별도의 라우터를 생성하고 이를 메인 애플리케이션에 포함시켜 사용할 수 있습니다.

3.1 라우터 생성

아래는 사용자를 관리하는 라우터를 만드는 예시입니다:


from fastapi import APIRouter

user_router = APIRouter()

@user_router.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 코드는 사용자의 정보를 가져오는 API를 정의하고 있습니다. APIRouter 클래스를 인스턴스화하여 user_router 객체를 생성한 후, 경로 함수와 응답 모델을 설정합니다.

3.2 메인 애플리케이션에 라우터 포함하기

생성한 라우터를 메인 FastAPI 애플리케이션에 연결하기 위해서는 include_router 메서드를 사용합니다:


app.include_router(user_router)

이제 메인 애플리케이션은 user_router에서 정의한 모든 경로를 사용할 수 있습니다.

4. 응답의 직렬화 및 검증

FastAPI는 Pydantic을 사용하여 응답 데이터를 자동으로 직렬화합니다. 기본적으로 객체는 JSON 형식으로 변환되어 클라이언트에게 전송됩니다. 이 과정에서 FastAPI는 데이터의 유효성을 검증하기 때문에, 클라이언트는 항상 일관된 데이터를 수신할 수 있습니다.

4.1 응답 예제

이제 실제로 API를 호출해보겠습니다. 사용자가 고유한 ID를 요청하면, 서버는 해당 사용자 정보를 JSON 형식으로 반환하게 됩니다. 예를 들어:


curl -X GET "http://localhost:8000/users/1"

위 요청에 대한 응답은 다음과 같을 것입니다:


{
    "id": 1,
    "username": "JohnDoe",
    "email": "john@example.com",
    "full_name": "John Doe"
}

4.2 에러 처리

FastAPI는 모델 검증 과정에서 문제가 발생하면 자동으로 오류 응답을 생성합니다. 예를 들어, 잘못된 데이터형을 요청하면:


curl -X GET "http://localhost:8000/users/not_a_number"

서버는 다음과 같은 오류 응답을 리턴합니다:


{
    "detail": [
        {
            "loc": ["path", "user_id"],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

5. 보안과 오류 관리

API 응답을 안전하게 유지하고 오류를 효과적으로 관리하는 것은 서버 개발의 핵심 요소입니다. FastAPI는 다양한 보안 기능을 제공하며, 모든 오류를 세밀하게 제어할 수 있는 방법을 갖추고 있습니다.

5.1 OAuth2 및 JWT 인증

FastAPI는 OAuth2 및 JWT를 사용한 인증을 지원합니다. 이를 통해 API 접근을 제한하고, 사용자 데이터를 보호할 수 있습니다.

5.2 사용자 정의 오류 응답

FastAPI는 사용자 정의 오류 처리를 쉽게 할 수 있도록 지원합니다. 아래와 같이 오류 발생 시 사용자 정의 응답을 리턴하도록 설정할 수 있습니다:


from fastapi import HTTPException

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    if user_id <= 0:
        raise HTTPException(status_code=400, detail="Invalid user ID")
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 예시는 사용자 ID가 유효하지 않을 경우 사용자 정의 오류를 발생시키는 예시입니다.

6. 마무리

FastAPI는 웹 API를 개발하는 데 많은 장점을 제공하며, 스키마 정의와 라우터를 이용한 구조적 접근 방식은 안정적이고 유지 보수가 용이한 코드를 만들 수 있게 합니다. 응답 스키마를 정의하고, 라우터를 포함하여 API 응답을 관리하는 방법에 대해 논의했습니다. 이러한 방법들을 통하여, 여러분은 더 나은 API를 설계할 수 있는 기초를 다졌을 것입니다.

FastAPI는 Python의 강력한 기능을 결합하여 웹 개발을 훨씬 용이하게 만들어 줍니다. 앞으로도 FastAPI와 함께 다양한 API를 개발해 보시길 바랍니다!