FastAPI 개발 환경 설정 (& poetry, ruff, pre-commit, SQLAlchemy)

034179·2024년 11월 9일

FastAPI를 처음 사용하며 프로젝트 환경 설정을 빠르게 하는데 도움을 드리기 위한 글입니다.
초기 프로젝트 환경 설정에서 어떠한 작업들을 왜 해야하는지에 대해 설명합니다.
또한 모든 기술은 프로젝트의 성격과 상황에 적합하게 선정하여 선택하시면 됩니다.
아래의 기술들은 일반적인 상황에서 추천드리는 선택지입니다.


목차

  1. Python 설치
  2. 가상환경 생성
  3. FastAPI 설치
  4. Ruff, pre-commit 설정
  5. 데이터베이스 설정 (& SQLAlchemy)

0. Python 설치

작성일인 24년도 11월 10일 기준, Python의 가장 최신 버전은 3.13입니다. 그리고 지난 10월에 3.8 버전은 EOL(End of Line)이 되었습니다.
프로젝트를 새로 시작한다면 적어도 Python3.10 이상의 버전을 추천드립니다.

아직 Python이 설치되어있지 않다면 아래의 링크에서 다운로드받으실 수 있습니다.

Python 공식 다운로드 페이지

Python이 설치되어있는지 확인하는 방법은 터미널에서 아래의 명령어를 실행하면 됩니다.

which python3
which python3.{설치한 버전}

명령어를 실행하면 Python이 설치된 경로를 확인할 수 있습니다.


1. 가상환경 생성

Python에서 가상환경을 만드는 방법은 pip, Pipenv(Pipfile 사용), Poetry가 있습니다.
가상환경 관리와 의존성 관리 측면에서 Poetry를 추천드립니다.

Poetry

Poetry는 Python 프로젝트의 의존성 관리와 가상환경 설정을 간편하게 해주는 도구입니다.

Poetry 설치

curl -sSL https://install.python-poetry.org | python3 -
brew install poetry

둘 중 하나만 실행하면 됩니다.
Mac인 경우는 brew를 통해 간편하게 설치할 수 있습니다. (물론 brew가 미리 설치되어 있어야합니다.)

Poetry 설정

프로젝트를 시작하고자 하는 디렉토리 경로에서 아래의 명령어들을 실행합니다.

poetry init

poetry init 명령어는 기존 프로젝트에 Poetry를 초기화하여 의존성을 관리하도록 설정합니다.
그리고 Python 프로젝트의 설정 및 의존성 관리 파일인 pyproject.toml를 생성합니다.

poetry install

pyproject.toml에 명시된 의존성을 설치하며, 만약 가상환경이 없다면 자동으로 생성하고 그 안에 의존성을 설치합니다.
즉, 처음 실행 시 가상환경을 생성합니다.

가상환경을 활성화 한 후 필요한 패키지를 설치하면 됩니다.

poetry shell
poetry add {패키지명}

명령어 정리

# Poetry 설치
> curl -sSL https://install.python-poetry.org | python3 -
> brew install poetry

# Poetry 초기화
> poetry init

# 가상환경 생성 및 의존성 설치
> poetry install

# 가상환경 활성화
> poetry shell

# 가상환경 비활성화
> exit

# 패키지 설치
> poetry add {패키지명}

# poetry.toml & pyproject.lock 동기화
> poetry lock --no-update

[더 알아보기] poetry lock과 poetry lock --no-update의 차이
개발을 하다보면 ‘poetry.lock이 최신 상태가 아닙니다.’ 경고가 발생할 때가 있다.
poetry lock 혹은 poetry lock --no-update을 실행하면 해결된다.

  • poetry lock
    poetry lockpyproject.toml에 정의된 패키지의 가능한 최신 버전poetry.lock에 반영합니다.
    예를 들어, pyproject.tomlfastapi = "^0.70.0"이라고 되어 있고, 현재 poetry.lock 파일에는 fastapi = "0.70.0"이 기록되어 있습니다.
    - 이 상태에서 poetry lock을 실행하면, FastAPI의 최신 버전인 0.75.0이 사용 가능한 경우 poetry.lock 파일을 fastapi = "0.75.0"으로 갱신합니다.
    - 즉, poetry.lock 파일이 최신 버전으로 업데이트됩니다.

  • poetry lock --no-update
    poetry lock --no-update는 현재 poetry.lock 파일에 기록된 버전을 그대로 유지하면서 pyproject.toml과의 동기화만 수행합니다.
    위의 예에서, poetry.lock 파일에 이미 fastapi = "0.70.0"이 기록되어 있다면, poetry lock --no-update를 실행해도 FastAPI 버전은 0.70.0으로 유지됩니다.
    이 명령어는 새로운 패키지를 추가하거나 제거할 때 기존 버전은 그대로 두면서, 변경된 부분만 반영하는 데 유용합니다.


    협업 시 버전 통일을 위하여 poetry lock 보다는 poetry lock --no-update를 추천드립니다.

[TIP] PyCharm을 사용하면 간편하게 프로젝트를 생성할 수 있다.
사진과 같이 프레임워크, 가상환경, 인터프리터 설정을 한 후 Create로 생성 시 라이브러리 설치 및 기본 코드 파일이 생성됩니다.


2. FastAPI 설치

라이브러리 설치

가상환경이 활성화된 상태에서 아래의 명령어를 실행합니다.

poetry add fastapi uvicorn

FastAPI 애플리케이션을 실행하기 위해 필요한 fastapi와 ASGI 서버인 uvicorn을 설치합니다.

FastAPI 코드

main.py 파일을 생성한 후 아래의 코드를 입력합니다.

# main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}


@app.get("/hello/{name}")
async def say_hello(name: str):
    return {"message": f"Hello {name}"}

아래의 명령어로 fastapi 서버를 실행시킵니다.

uvicorn main:app --reload

http://127.0.0.1:8000/docs 에 접속하면 자동 생성된 Swagger 문서를 확인할 수 있습니다.


3. Ruff, pre-commit 설정

Ruff

Ruff는 Python 코드의 린팅과 포매팅을 빠르고 효율적으로 수행하는 도구로, Pylint, Flake8, Black 같은 다양한 스타일 검사 기능을 통합하여 제공합니다.

pre-commit

pre-commit을 사용하면 커밋 전에 자동으로 Ruff를 실행하여 코드 스타일을 검사하거나 포매팅할 수 있습니다.

라이브러리 설치

가상환경이 활성화된 상태에서 아래의 명령어를 실행합니다.

poetry add --group dev ruff pre-commit

ruffpre-commit개발 중에만 필요한 도구로, 실제 애플리케이션이 실행되는 프로덕션 환경에서는 필요하지 않습니다.

dev 그룹으로 설치하면 프로덕션 배포 시 의존성 목록에서 제외할 수 있어, 애플리케이션 크기를 줄일 수 있습니다.

Ruff 설정

Ruff의 설정은 프로젝트 루트에 .ruff.toml 파일을 생성하거나, pyproject.toml 파일의 [tool.ruff] 섹션에 추가하여 구성할 수 있습니다

Poetry를 사용하므로 모든 설정을 한 곳에서 관리하는 방법인 pyproject.toml 파일에서 설정하는 것을 추천드립니다.

# pyproject.toml
[tool.ruff]
line-length = 120
exclude = [
    ".git",
    "__pycache__",
    "tests/*"
]
lint.ignore = ["F401", "E402", "E501"]
lint.select = ["I", "E", "F", "W", "C90"]

위의 설정은 예시 설정이며, 팀의 코드 스타일이나 본인의 프로젝트에 적합하게 설정하면 됩니다.

  • line-length: 줄 길이 제한 설정
  • exclude: 제외할 폴더나 파일
  • lint.ignore: 특정 에러 코드 무시
  • lint.select: 검사할 규칙 선택
    • "I": 임포트 관련 규칙 검사
    • "E": 코드 스타일 검사, 주로 PEP 8 스타일 문제와 관련된 규칙 검사
    • "F": 일반적인 Python 코드 오류
    • "W": 잠재적인 경고를 생성할 수 있는 요소
    • "C90": 코드의 복잡도와 관련된 문제 검사

Ruff 실행

가상환경이 활성화 되어있다면, poetry run 명령어를 생략할 수 있습니다.

# Poetry 가상환경 내에서 Ruff 실행하기
> poetry run ruff check .

# Import 구문 순서 정렬 및 코드 수정 자동화
> poetry run ruff check . --fix

# 특정 파일/디렉토리만 검사
> poetry run ruff check path/to/file.py

pre-commit 설정

pre-commit 설정은 .pre-commit-config.yaml 파일에서만 할 수 있습니다.

.pre-commit-config.yaml 파일을 생성 후 아래의 코드를 작성합니다.

repos:
  - repo: https://github.com/charliermarsh/ruff-pre-commit
    rev: "v0.7.1"
    hooks:
      - id: ruff
        args: ["--fix"]

아래의 명령어를 실행하여 pre-commit을 활성화합니다.

poetry run pre-commit install

이제 커밋할 때마다 자동으로 Ruff가 실행됩니다.

4. 데이터베이스 설정

진행하는 프로젝트에 적합한 데이터베이스를 선정하여 설정하시면 됩니다.

해당 글에서는 예시로 SQLite를 사용합니다.
SQLite는 Python에 기본적으로 내장되어 있어 별도의 설치 없이 사용 가능합니다.

ORM 설정

ORM(Object-Relational Mapping)이란,
데이터베이스의 테이블을 객체 지향 프로그래밍 언어의 클래스와 매핑하여 SQL 없이도 데이터베이스 작업을 객체로 조작할 수 있습니다.

FastAPI에서 일반적으로 사용하는 ORM 라이브러리는 주로 SQLAlchemy, Tortoise ORM, SQLModel이 있습니다.

[더 알아보기] SQLAlchemy, Tortoise ORM, SQLModel

  • SQLAlchemy
    SQLAlchemy는 Python에서 가장 널리 사용되는 ORM입니다.
    다양한 관계형 데이터베이스와 호환되며 복잡한 쿼리 작성을 지원합니다.
  • Tortoise ORM
    비동기 처리에 특화된 ORM이며 Django ORM과 유사한 문법을 제공합니다.
  • SQLModel
    FastAPI의 창시자가 만든 ORM 라이브러리, SQLAlchemy와 Pydantic을 결합하여 데이터베이스 모델을 Pydantic 모델로도 사용할 수 있게 설계되었습니다.
    21년도에 개발되어 작성일 기준 최신 버전은 0.0.22입니다.

해당 글에서는 예시로 SQLAlchemy를 사용합니다.
또한 환경변수를 관리하기 위해 python-dotenv 라이브러리를 사용합니다.

poetry add sqlalchemy python-dotenv
# .env
# DATABASE SETUP
DATABASE_URL=sqlite:///./test.db  # SQLite 예시 URL
# .env.sample
# DATABASE SETUP
DATABASE_URL=

.env 파일에 필요한 환경변수를 작성하며, .env 파일은 .gitignore에 추가하셔야합니다.
또한 협업을 위하여 어떠한 변수를 사용해야 하는지 알 수 있도록 .env.sample 파일을 만드시는 것을 추천드립니다.


database.py 파일 생성 후 데이터베이스 연결 및 설정 코드를 작성합니다.

# database.py
import os

from dotenv import load_dotenv
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

load_dotenv()

# 데이터베이스 URL 설정
SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URL")
if not SQLALCHEMY_DATABASE_URL:
    raise ValueError("DATABASE_URL 환경 변수가 설정되지 않았습니다.")

# 데이터베이스 엔진 생성
# 데이터베이스 설정에 따라 변경할 것
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})  # SQLite 엔진 설정

# 세션 로컬 생성
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 베이스 모델 생성
Base = declarative_base()

# 모델과 데이터베이스 테이블을 동기화하는 함수
def init_db():
    Base.metadata.create_all(bind=engine)

# 데이터베이스 세션 의존성 설정하는 함수
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

init_db() 함수를 main.py에 추가합니다.

# main.py
from fastapi import FastAPI

app = FastAPI()

init_db()

0개의 댓글