FastAPI를 이용한 TDD 개발 - 5

2024. 3. 14. 11:18·프로그래밍 언어/파이썬

App Structure

테스트가 잘 수행 되었면 앱을 리팩터링하고 FastAPI의 APIRouter, 새로운 데이터베이스 초기화 함수 및 pydantic 모델을 추가해 보겠습니다.

 

API라우터

먼저 "app" 폴더에 "api"라는 새 폴더를 추가합니다. 새로 생성된 폴더에 __init__.py 파일을 추가합니다 .

이제 경로를 project/app/api/ping.py/ping 라는 새 파일로 이동할 수 있습니다 .

# project/app/api/ping.py


from fastapi import APIRouter, Depends

from app.config import get_settings, Settings


router = APIRouter()


@router.get("/ping")
async def pong(settings: Settings = Depends(get_settings)):
    return {
        "ping": "pong!",
        "environment": settings.environment,
        "testing": settings.testing
    }

 

그런 다음 main.py를 업데이트하여 이전 경로를 제거하고 라우터를 기본 앱에 연결한 다음 함수를 사용하여 새 앱을 초기화합니다.

 

# project/app/main.py


import os

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise

from app.api import ping


def create_application() -> FastAPI:
    application = FastAPI()

    register_tortoise(
        application,
        db_url=os.environ.get("DATABASE_URL"),
        modules={"models": ["app.models.tortoise"]},
        generate_schemas=False,
        add_exception_handlers=True,
    )

    application.include_router(ping.router)

    return application


app = create_application()

http://localhost:8004/ping 및 http://localhost:8004/docs가 여전히 작동하는지 확인하세요 .

 

 

테스트 목적으로 FastAPI의 새 인스턴스를 생성하는 ` create_application`  함수를 사용하려면 project/tests/conftest.pytest_app 의 픽스처를 업데이트합니다 .

 

# project/tests/conftest.py


import os

import pytest
from starlette.testclient import TestClient

from app.main import create_application  # updated
from app.config import get_settings, Settings


def get_settings_override():
    return Settings(testing=1, database_url=os.environ.get("DATABASE_TEST_URL"))


@pytest.fixture(scope="module")
def test_app():
    # set up
    app = create_application()  # new
    app.dependency_overrides[get_settings] = get_settings_override
    with TestClient(app) as test_client:  # updated

        # testing
        yield test_client

    # tear down

 

여전히 테스트가 통과되는지 확인해 봅니다. 

$ docker-compose exec web python -m pytest

=============================== test session starts ===============================
platform linux -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0
rootdir: /usr/src/app
plugins: anyio-4.2.0
collected 1 item

tests/test_ping.py .                                                        [100%]

================================ 1 passed in 0.16s ================================

 

프로젝트 구조는 아래와 같습니다. 

├── .gitignore
├── docker-compose.yml
└── project
    ├── .dockerignore
    ├── Dockerfile
    ├── app
    │   ├── __init__.py
    │   ├── api
    │   │   ├── __init__.py
    │   │   └── ping.py
    │   ├── config.py
    │   ├── db.py
    │   ├── main.py
    │   └── models
    │       ├── __init__.py
    │       └── tortoise.py
    ├── db
    │   ├── Dockerfile
    │   └── create.sql
    ├── entrypoint.sh
    ├── migrations
    │   └── models
    │       └── 0_20211227001140_init.sql
    ├── pyproject.toml
    ├── requirements.txt
    └── tests
        ├── __init__.py
        ├── conftest.py
        └── test_ping.py

 

 

Database 초기화

register_tortoise 헬퍼함수가 있는 db.py를 수정합니다. 

# project/app/db.py


import os

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise


TORTOISE_ORM = {
    "connections": {"default": os.environ.get("DATABASE_URL")},
    "apps": {
        "models": {
            "models": ["app.models.tortoise", "aerich.models"],
            "default_connection": "default",
        },
    },
}


def init_db(app: FastAPI) -> None:
    register_tortoise(
        app,
        db_url=os.environ.get("DATABASE_URL"),
        modules={"models": ["app.models.tortoise"]},
        generate_schemas=False,
        add_exception_handlers=True,
    )

 

init_db 함수를 main.py로 임포트합니다.

# project/app/main.py


import logging

from fastapi import FastAPI

from app.api import ping
from app.db import init_db


log = logging.getLogger("uvicorn")


def create_application() -> FastAPI:
    application = FastAPI()
    application.include_router(ping.router)

    return application


app = create_application()


@app.on_event("startup")
async def startup_event():
    log.info("Starting up...")
    init_db(app)


@app.on_event("shutdown")
async def shutdown_event():
    log.info("Shutting down...")

 

테스트하려면 먼저 컨테이너와 볼륨을 종료합니다.

 

$ docker-compose down -v

 

그런 다음 컨테이너를 다시 가져옵니다.

$ docker-compose up -d --build

 

마이그레이션을 적용하지 않았으므로 데이터베이스에 테이블이 표시되지 않습니다.

$ docker-compose exec web-db psql -U postgres

psql (16.1)
Type "help" for help.

postgres=# \c web_dev
You are now connected to database "web_dev" as user "postgres".

web_dev=# \dt
Did not find any relations.

web_dev=# \q

 

속도가 느려질 수 있는 Aerich를 통한 마이그레이션을 적용하는 대신 최종 상태의 데이터베이스에 스키마를 적용하려는 경우가 있을 수 있습니다. 따라서 이를 처리하기 위해 db.py에 generate_schema 함수를 추가해 보겠습니다 .

 

# project/app/db.py


import logging  # new
import os

from fastapi import FastAPI
from tortoise import Tortoise, run_async  # new
from tortoise.contrib.fastapi import register_tortoise


log = logging.getLogger("uvicorn") # new


TORTOISE_ORM = {
    "connections": {"default": os.environ.get("DATABASE_URL")},
    "apps": {
        "models": {
            "models": ["app.models.tortoise", "aerich.models"],
            "default_connection": "default",
        },
    },
}


def init_db(app: FastAPI) -> None:
    register_tortoise(
        app,
        db_url=os.environ.get("DATABASE_URL"),
        modules={"models": ["app.models.tortoise"]},
        generate_schemas=False,
        add_exception_handlers=True,
    )


# new
async def generate_schema() -> None:
    log.info("Initializing Tortoise...")

    await Tortoise.init(
        db_url=os.environ.get("DATABASE_URL"),
        modules={"models": ["models.tortoise"]},
    )
    log.info("Generating database schema via Tortoise...")
    await Tortoise.generate_schemas()
    await Tortoise.close_connections()


# new
if __name__ == "__main__":
    run_async(generate_schema())

 

Tortoise.init 함수 호출을 위해서 generate_schema 함수가 먼저 호출됩니다. 그리고 tortoise 설정이 된다음 스키마가 생성됩니다. 

$ docker-compose exec web python app/db.py

 

스키마가 있는지 확인해 봅니다.

$ docker-compose exec web-db psql -U postgres

psql (16.1)
Type "help" for help.

postgres=# \c web_dev
You are now connected to database "web_dev" as user "postgres".

web_dev=# \dt
            List of relations
 Schema |    Name     | Type  |  Owner
--------+-------------+-------+----------
 public | textsummary | table | postgres
(1 row)

web_dev=# \q

 

개발에서는 Aerich를 이용할 것이므로 다시 컨테이너 볼륨을 내려줍니다. 

$ docker-compose down -v

 

다시 이미지를 빌드하고 컨테이너를 기동합니다. 

$ docker-compose up -d --build

 

데이터베이스에 테이블이 없는지 확인합니다. 그런 다음 마이그레이션을 적용합니다.

$ docker-compose exec web aerich upgrade

 

aerich와 testsummary 테이블이 이제 존재하는지 확인합니다. 

 

Pydantic Model

models 패키지 내에 pydantic 파일 안에 새로운 pydantic 모델을 만듭니다.

# project/app/models/pydantic.py


from pydantic import BaseModel


class SummaryPayloadSchema(BaseModel):
    url: str
저작자표시 (새창열림)

'프로그래밍 언어 > 파이썬' 카테고리의 다른 글

FastAPI를 이용한 TDD 개발 - 8  (0) 2024.03.14
FastAPI를 이용한 TDD 개발 - 6  (0) 2024.03.14
FastAPI를 이용한 TDD 개발 - 4  (0) 2024.03.14
FastAPI를 이용한 TDD 개발 - 3  (0) 2024.03.12
FastAPI를 이용한 TDD 개발 - 2  (0) 2024.03.11
'프로그래밍 언어/파이썬' 카테고리의 다른 글
  • FastAPI를 이용한 TDD 개발 - 8
  • FastAPI를 이용한 TDD 개발 - 6
  • FastAPI를 이용한 TDD 개발 - 4
  • FastAPI를 이용한 TDD 개발 - 3
hyeseong-dev
hyeseong-dev
안녕하세요. 백엔드 개발자 이혜성입니다.
  • hyeseong-dev
    어제 오늘 그리고 내일
    hyeseong-dev
  • 전체
    오늘
    어제
    • 분류 전체보기 (286)
      • 여러가지 (107)
        • 알고리즘 & 자료구조 (72)
        • 오류 (4)
        • 이것저것 (29)
        • 일기 (1)
      • 프레임워크 (39)
        • 자바 스프링 (39)
        • React Native (0)
      • 프로그래밍 언어 (38)
        • 파이썬 (30)
        • 자바 (3)
        • 스프링부트 (5)
      • 컴퓨터 구조와 운영체제 (3)
      • DB (17)
        • SQL (0)
        • Redis (17)
      • 클라우드 컴퓨팅 (2)
        • 도커 (2)
        • AWS (0)
      • 스케쥴 (65)
        • 세미나 (0)
        • 수료 (0)
        • 스터디 (24)
        • 시험 (41)
      • 트러블슈팅 (1)
      • 자격증 (0)
        • 정보처리기사 (0)
      • 재태크 (5)
        • 암호화폐 (5)
        • 기타 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Docker-compose
    완전탐색
    프로그래머스
    spring
    reactor
    그리디
    시험
    celery
    ecs
    FastAPI
    Spring Boot
    파이썬
    RDS
    EC2
    취업리부트
    Python
    AWS
    DP
    #개발자포트폴리오 #개발자이력서 #개발자취업 #개발자취준 #코딩테스트 #항해99 #취리코 #취업리부트코스
    Redis
    docker
    Spring WebFlux
    WebFlux
    자바
    SAA
    OOP
    mybatis
    백준
    항해99
    java
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
hyeseong-dev
FastAPI를 이용한 TDD 개발 - 5
상단으로

티스토리툴바