FastAPI 서버개발, 비동기 대응 DB 접속 함수

FastAPI는 Python의 빠르고 현대적인 웹 프레임워크로, 비동기 프로그래밍을 통해 높은 성능을 발휘합니다. 이 글에서는 FastAPI에서 비동기 데이터베이스 접속 함수를 구현하는 방법에 대해 상세히 설명하고, 예제 코드를 통해 몸소 경험할 수 있도록 하겠습니다. FastAPI의 비동기 기능은 대규모 웹 애플리케이션이나 높은 동시성이 요구되는 API 서버를 구축할 때 특히 강력한 성능을 제공합니다.

1. 비동기 프로그래밍이란?

비동기 프로그래밍은 여러 작업을 동시에 처리할 수 있게 해주는 프로그래밍 모델입니다. 기존의 동기 프로그래밍에서는 작업 하나가 끝날 때까지 다음 작업을 기다려야 했지만, 비동기 프로그래밍에서는 하나의 작업이 진행되는 동안 다른 작업을 동시에 처리할 수 있습니다. 이는 특히 I/O 바운드 작업에서 큰 이점을 제공합니다.

1.1 비동기 프로그래밍의 장점

  • 성능 증가: 여러 I/O 작업을 동시에 처리하여 대기 시간을 줄일 수 있습니다.
  • 리소스 효율성: CPU 사용률을 최적화하고, 낮은 자원으로 많은 클라이언트를 처리할 수 있습니다.
  • 응답성 향상: 서버가 특정 작업을 기다리는 시간이 줄어들어 사용자가 더 빠르게 응답을 받을 수 있습니다.

2. FastAPI 소개

FastAPI는 Python 3.6+을 위한 현대적인 웹 프레임워크로, 빠르고, 직관적이며, 자동 완성을 제공합니다. FastAPI의 가장 큰 장점 중 하나는 ASGI(Asynchronous Server Gateway Interface)를 기반으로 하여 비동기 처리를 지원한다는 것입니다. 이는 웹 소켓이나 데이터베이스와 같은 비동기 I/O를 처리하는 데 매우 유리합니다.

FastAPI는 또한 Pydantic을 사용하여 데이터 유효성을 검사하고 JSON 직렬화를 제공하여 개발자가 보다 간편하게 API를 개발할 수 있도록 돕습니다.

3. 비동기 데이터베이스 접근 방법

데이터베이스에 비동기적으로 접근하기 위해서는 비동기 지원을 위한 ORM(Object Relational Mapping) 라이브러리를 사용해야 합니다. 여기서는 SQLAlchemyDatabases 라이브러리를 조합하여 비동기 DB 접속 함수를 구현하는 예제를 살펴보겠습니다.

3.1 필요한 라이브러리 설치

FastAPI 애플리케이션을 시작하기 위해 필요한 패키지를 설치합니다. 다음과 같은 명령어를 터미널에 입력하여 설치합니다:

pip install fastapi uvicorn sqlalchemy databases asyncpg

위 명령어는 FastAPI 프레임워크, ASGI 서버(Uvicorn), SQLAlchemy ORM, Databases 비동기 라이브러리, PostgreSQL 데이터베이스 드라이버를 설치합니다.

3.2 데이터베이스 모델 설정

이제 비동기 작업을 수행할 데이터베이스 모델을 정의하겠습니다. SQLAlchemy를 사용하여 데이터베이스 모델을 작성합니다.

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True, index=True)

3.3 데이터베이스 연결 설정

비동기 데이터베이스 연결을 위해 Databases 라이브러리를 사용하여 데이터베이스 연결을 설정합니다.

DATABASE_URL = "postgresql+asyncpg://user:password@localhost/dbname"
database = Database(DATABASE_URL)
engine = create_engine(DATABASE_URL)
Base.metadata.create_all(bind=engine)

위 코드에서 DATABASE_URL은 사용자의 데이터베이스 정보를 입력해야 합니다. 데이터베이스 사용자가 user, 비밀번호가 password이며, 데이터베이스 이름이 dbname인 PostgreSQL 데이터베이스에 연결하는 URI입니다.

3.4 비동기 데이터베이스 함수 구현

이제 필요한 비동기 데이터베이스 작업 함수를 구현합니다.

from databases import Database

async def get_user(database: Database, user_id: int):
    query = "SELECT * FROM users WHERE id = :id"
    return await database.fetch_one(query, values={"id": user_id})

async def create_user(database: Database, username: str, email: str):
    query = "INSERT INTO users(username, email) VALUES (:username, :email)"
    await database.execute(query, values={"username": username, "email": email})

위 함수는 각각 사용자를 데이터베이스에서 조회하고, 새 사용자를 생성하는 비동기 함수입니다. fetch_one 메소드는 데이터베이스 쿼리에 대한 단일 결과를 비동기적으로 반환하고, execute 메소드는 INSERT 작업을 수행합니다.

3.5 FastAPI 앱과 비동기 데이터베이스 함수 연결

FastAPI 애플리케이션을 설정하고, 비동기 데이터베이스 함수를 해당 엔드포인트에 연결합니다.

from fastapi import FastAPI

app = FastAPI()

@app.on_event("startup")
async def startup():
    await database.connect()

@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    user = await get_user(database, user_id)
    return user

@app.post("/users/")
async def create_new_user(username: str, email: str):
    await create_user(database, username, email)
    return {"msg": "User created successfully"}

위 코드에서 애플리케이션의 시작 시 database.connect()를 호출하여 데이터베이스에 연결하고, 종료 시 database.disconnect()를 호출하여 연결을 종료합니다. 사용자를 조회하는 read_user 엔드포인트와 새 사용자를 생성하는 create_new_user 엔드포인트도 설정했습니다.

4. 테스트와 검증

이제 FastAPI 애플리케이션을 실행하고 비동기 API를 테스트할 준비가 되었습니다. 다음 명령어로 서버를 실행합니다:

uvicorn main:app --reload

웹 브라우저에서 http://localhost:8000/docs에 접속하면 FastAPI의 문서화된 API 인터페이스를 확인할 수 있습니다. 여기서 비동기적으로 정의한 API를 테스트할 수 있습니다.

4.1 사용자 생성 테스트

/users/ 엔드포인트로 POST 요청을 보내어 사용자를 생성할 수 있습니다. 예시 요청 본문은 다음과 같습니다:

{
    "username": "testuser",
    "email": "test@example.com"
}

4.2 사용자 조회 테스트

/users/{user_id} 엔드포인트로 GET 요청을 보내어 사용자를 조회할 수 있습니다. 예를 들어 /users/1 요청을 보내면 ID가 1인 사용자의 정보를 받을 수 있습니다.

5. 결론

FastAPI 모바일 애플리케이션을 위한 강력하고 효율적인 백엔드 서버를 구축하는 데 필요한 기본적인 비동기 데이터베이스 접속 함수를 성공적으로 구현했습니다. 이 예제를 통해 FastAPI의 비동기 기능을 활용하여 동시성을 높이고, 더 많은 클라이언트 요청을 처리할 수 있는 옵션을 갖추게 되었습니다. 이러한 구조는 특히 트래픽이 높은 애플리케이션에서 성능을 극대화할 수 있습니다.

추가적으로, 데이터베이스와의 비동기 작업을 위한 다양한 라이브러리와 기술도 존재하므로, 각각의 요구사항에 맞게 커스터마이징하여 사용하시기 바랍니다. 이 글이 여러분의 FastAPI 개발에 도움이 되기를 바랍니다.