FastAPI 서버개발, 도커파일 작성

FastAPI는 파이썬으로 작성된 현대적인 웹 프레임워크로, 빠른 성능과 직관적인 API 설계를 제공합니다. 이번 강좌에서는 FastAPI를 사용하여 간단한 웹 서버를 개발하고, 이를 도커로 감싸 배포하는 방법을 알아보겠습니다. 전체 과정은 크게 세 부분으로 나눌 수 있습니다:

  • FastAPI 서버 개발
  • FastAPI 서버의 기능 구현
  • 도커파일 작성 및 컨테이너화

1. FastAPI 서버 개발

1.1 FastAPI 설치

FastAPI를 사용하기 위해서는 먼저 FastAPI와 UVicorn(ASGI 서버)을 설치해야 합니다. 다음 명령어를 사용하여 설치할 수 있습니다:

pip install fastapi uvicorn

1.2 기본 FastAPI 서버 설정

아래의 간단한 예제는 기본적인 FastAPI 서버를 설정하는 방법을 보여줍니다:

from fastapi import FastAPI

app = FastAPI()

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

위 코드는 가장 기본적인 FastAPI 서버로, 루트 URL(“/”)에 GET 요청을 보내면 JSON 형식으로 {“Hello”: “World”}를 반환합니다.

1.3 서버 실행

이제 서버를 실행해 보겠습니다. 아래와 같은 명령어로 서버를 시작할 수 있습니다:

uvicorn main:app --reload

여기서 main은 Python 파일의 이름(확장자 제외)이며, app은 FastAPI 인스턴스의 이름입니다. --reload 플래그는 코드 변경 시 자동으로 서버를 다시 시작합니다.

2. FastAPI 서버의 기능 구현

2.1 RESTful API 설계

FastAPI는 RESTful API 설계에 매우 유용합니다. 다음 단계에서는 사용자 관리 API를 구현해 보겠습니다.

2.2 데이터 모델 정의

FastAPI에서는 Pydantic을 사용하여 데이터 유효성 검사를 수행하는 모델을 정의할 수 있습니다. 사용자 모델을 정의해 보겠습니다:

from pydantic import BaseModel
from typing import List, Optional

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

2.3 CRUD API 구현

다음으로 간단한 CRUD(Create, Read, Update, Delete) API를 만들어 보겠습니다. 사용자를 저장할 리스트를 만들고, 각 API 엔드포인트를 정의하겠습니다:

from fastapi import FastAPI, HTTPException

app = FastAPI()
users = []

@app.post("/users/", response_model=User)
async def create_user(user: User):
    users.append(user)
    return user

@app.get("/users/", response_model=List[User])
async def get_users():
    return users

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    for user in users:
        if user.id == user_id:
            return user
    raise HTTPException(status_code=404, detail="User not found")

@app.put("/users/{user_id}", response_model=User)
async def update_user(user_id: int, user: User):
    for index, u in enumerate(users):
        if u.id == user_id:
            users[index] = user
            return user
    raise HTTPException(status_code=404, detail="User not found")

@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    for index, u in enumerate(users):
        if u.id == user_id:
            del users[index]
            return {"message": "User deleted"}
    raise HTTPException(status_code=404, detail="User not found")

위 코드는 사용자를 생성, 조회, 수정 및 삭제하는 API를 구현합니다. 각 API는 적절한 HTTP 상태 코드를 반환합니다.

3. 도커파일 작성 및 컨테이너화

3.1 도커 설치

도커를 사용하기 위해서는 먼저 도커를 설치해야 합니다. 공식 웹사이트에서 설치 방법을 참고할 수 있습니다.

3.2 도커파일 작성

도커는 애플리케이션을 컨테이너화하여 쉽게 배포할 수 있게 도와줍니다. FastAPI 애플리케이션을 위한 도커파일을 작성해 보겠습니다. 파일 이름은 Dockerfile로 설정합니다:

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9

COPY ./app /app

# 설정된 작업 디렉토리
WORKDIR /app

# 필요한 의존성 설치
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 실행
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

도커파일에서 FROM 지시어는 사용할 기본 이미지를 결정합니다. COPY 지시어는 코드를 컨테이너에 복사하며, RUN 지시어는 필요한 라이브러리를 설치합니다. 마지막으로 CMD 지시어는 컨테이너가 시작될 때 실행되는 명령을 지정합니다.

3.3 요구 사항 파일 작성

다음으로 FastAPI와 UVicorn을 포함하는 requirements.txt 파일을 생성합니다:

fastapi
uvicorn

3.4 도커 이미지 빌드

이제 도커 이미지를 빌드할 차례입니다. 아래 명령어를 사용하여 이미지를 빌드합니다:

docker build -t myfastapiapp .

3.5 컨테이너 실행

컨테이너를 실행하려면 먼저 도커가 실행 중인지 확인한 후 다음 명령어를 입력합니다:

docker run -d --name fastapi-container -p 80:80 myfastapiapp

이렇게 하면 FastAPI 애플리케이션이 도커 컨테이너에서 실행됩니다. 웹 브라우저에서 http://localhost를 열면 API에 접속할 수 있습니다.

결론

이번 강좌에서는 FastAPI를 이용한 서버 개발 방법과 도커파일 작성 및 컨테이너화하는 과정을 살펴보았습니다. FastAPI는 직관적인 문법과 성능 덕분에 많은 개발자에게 사랑받고 있으며, 도커를 사용하면 쉽게 배포할 수 있습니다. 이를 통해 실제 운영 환경에서도 쉽게 사용할 수 있는 백엔드 서버를 구축할 수 있습니다.

FastAPI 서버개발, CORS 설정

FastAPI는 현대적인 웹 API를 쉽게 구축할 수 있도록 돕는 Python 기반의 프레임워크입니다. 이 프레임워크는 높은 성능을 자랑하며, 데이터 검증, 자동 문서화 등의 기능을 제공합니다. 본 글에서는 FastAPI 서버 개발 과정에서 마주칠 수 있는 CORS(Cross-Origin Resource Sharing) 설정에 대해 자세히 설명하고, 이를 통해 다양한 클라이언트(웹 브라우저 등)에서 API를 안전하게 접근할 수 있도록 하는 방법을 다루겠습니다.

CORS란 무엇인가?

CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 서로 다른 출처(origin)에서 리소스를 요청할 수 있게 하는 보안 기능입니다. 예를 들어, 만약 http://example.com에서 호스팅되는 웹 애플리케이션이 http://api.example.com으로 요청을 보낼 경우, 두 URL의 출처가 다르기 때문에 기본적으로 차단됩니다. 이를 해결하기 위해 CORS를 설정하여 특정 출처에서 API를 접근할 수 있도록 허용할 수 있습니다.

CORS의 필요성

CORS는 보안상의 이유로 구현되어 있습니다. 사용자가 스스로 모르는 사이에 악성 스크립트가 다른 도메인에 있는 데이터에 접근하는 것을 방지하기 위함입니다. 하지만 웹 애플리케이션에서는 여러 서비스와 상호작용을 위해 다른 출처와 연결할 필요가 있습니다. 따라서, 올바른 CORS 정책을 설정하는 것이 중요합니다.

FastAPI에서 CORS 설정하기

FastAPI에서는 fastapi.middleware.cors 모듈의 CORSMiddleware 클래스를 사용하여 쉽게 CORS 정책을 설정할 수 있습니다. 아래의 단계를 통해 FastAPI 애플리케이션에 CORS를 추가하는 방법을 살펴보겠습니다.

1. FastAPI 설치하기

FastAPI 및 기타 필요한 라이브러리를 우선 설치해야 합니다. 아래의 명령어를 터미널에 입력하여 FastAPI와 uvicorn을 설치합니다.

pip install fastapi uvicorn

2. 기본 FastAPI 애플리케이션 생성하기

아래의 코드는 FastAPI 애플리케이션을 간단히 설정하는 예제입니다.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

3. CORS 미들웨어 추가하기

CORS를 설정하기 위해 CORSMiddleware를 FastAPI 애플리케이션에 추가합니다. `allow_origins` 매개변수를 사용하여 허용할 출처를 지정할 수 있습니다.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# CORS 설정
origins = [
    "http://localhost:3000",
    "https://myfrontend.com",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # 허용할 출처
    allow_credentials=True,
    allow_methods=["*"],  # 허용할 HTTP 메서드
    allow_headers=["*"],  # 허용할 헤더
)

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

4. CORS 설정 옵션 설명하기

  • allow_origins: 요청을 허용할 출처를 명시합니다. 도메인 이름이나 와일드카드(*)를 사용할 수 있습니다.
  • allow_credentials: 쿠키 및 인증 정보를 포함한 요청을 허용할지 여부를 설정합니다.
  • allow_methods: 허용할 HTTP 메서드를 설정합니다. 기본값은 GET, POST입니다.
  • allow_headers: 클라이언트가 요청할 수 있는 헤더를 지정합니다.

5. 다양한 환경에서의 CORS 설정 예제

개발 환경, 테스트 환경, 운영 환경에 따라 CORS 설정을 다르게 할 수 있습니다. 예를 들어, 개발 환경에서는 로컬 출처만을 허용하고, 운영 환경에서는 여러 도메인을 허용할 수 있습니다. 아래는 상황에 따라 다르게 설정하는 예제입니다.

import os
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 환경에 따라 CORS 설정을 변경
if os.getenv("ENV") == "production":
    origins = [
        "https://myfrontend.com",
        "https://anotherdomain.com",
    ]
else:
    origins = [
        "http://localhost:3000",
    ]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

6. CORS 관련 문제 해결하기

CORS 설정을 제대로 해도 가끔 원하는 대로 동작하지 않을 수 있습니다. 이때 확인해야 할 몇 가지 사항이 있습니다.

  • 브라우저 콘솔 로그: 브라우저의 개발자 도구를 열고, 콘솔 탭에서 CORS 관련 에러 메시지를 확인합니다.
  • 서버 로그: FastAPI 서버의 로그 파일을 점검하여 요청이 서버에 도달했는지 확인합니다.
  • 네트워크 요청 확인: 개발자 도구의 네트워크 탭에서 요청 헤더와 응답 헤더를 분석하여 문제를 파악합니다.

결론

FastAPI는 CORS 설정을 통해 웹 애플리케이션과 API 간의 안전한 통신을 가능하게 합니다. 올바른 CORS 정책을 설정하여 다양한 출처의 클라이언트가 API를 접근할 수 있도록 하는 것이 중요합니다. 본 글에서 설명한 내용을 통해 FastAPI에서 CORS를 간단하게 설정하고 문제를 해결하는 데 도움이 되길 바랍니다.

FastAPI 서버개발, 도커 이미지 빌드

FastAPI는 현대적인 웹 애플리케이션을 구축하는 데 있어 매우 인기 있는 Python 웹 프레임워크입니다. 이 강좌에서는 FastAPI를 사용하여 간단한 RESTful API를 만들고 이를 Docker를 사용해 배포하는 방법에 대해 설명하겠습니다. FastAPI는 탁월한 성능과 쉬운 사용성을 제공하며, Swagger UI, 자동 문서화 등 다양한 기능을 내장하고 있어 개발자에게 많은 이점을 제공합니다.

목차

1. FastAPI란 무엇인가?

FastAPI는 비동기 프로그래밍을 지원하는 Python 기반의 웹 프레임워크입니다. RESTful API를 쉽고 빠르게 개발할 수 있도록 설계되었습니다. FastAPI의 주요 특징은 다음과 같습니다:

  • 자동 API 문서화: Swagger UI를 통한 자동화된 문서화 지원
  • 높은 성능: Starlette 및 Pydantic을 기반으로 하여 높은 성능을 자랑
  • 비동기 처리 지원: async/await 구문을 이용해 비동기 코드를 쉽게 작성 가능
  • 데이터 검증: Pydantic을 통한 강력한 데이터 검증 기능

2. FastAPI 설치 및 환경 설정

FastAPI를 설치하기 위해서는 Python이 필요합니다. 터미널에서 다음 명령어를 입력하여 FastAPI와 Uvicorn을 설치합니다:

pip install fastapi uvicorn

설치가 완료되면, FastAPI 애플리케이션을 작성할 수 있는 기본 구조를 만듭니다.

mkdir fastapi_docker && cd fastapi_docker
touch main.py

이제 main.py 파일을 열고 기본적인 FastAPI 서버를 작성해 보겠습니다.

FastAPI 기본 서버 예제

from fastapi import FastAPI

app = FastAPI()

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

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "query": q}

위 코드는 간단한 FastAPI 서버를 정의합니다. / 경로에 GET 요청을 보내면 “Hello, World”라는 JSON 응답을 받고, /items/{item_id} 경로에 GET 요청을 보내면 해당 item_id과 쿼리 매개변수를 포함한 JSON 응답을 반환합니다.

3. FastAPI 애플리케이션 개발

FastAPI 애플리케이션을 좀 더 발전시켜 보겠습니다. 여기서는 간단한 Todo 애플리케이션을 구현해 보겠습니다. 아래는 Todo 애플리케이션의 기본 구조입니다.

Todo 모델 정의

from typing import List, Optional
from pydantic import BaseModel

class TodoItem(BaseModel):
    id: int
    title: str
    completed: bool = False

todos = []

Todo API 엔드포인트 구현

@app.post("/todos/", response_model=TodoItem)
async def create_todo(todo: TodoItem):
    todos.append(todo)
    return todo

@app.get("/todos/", response_model=List[TodoItem])
async def read_todos():
    return todos

@app.delete("/todos/{todo_id}")
async def delete_todo(todo_id: int):
    global todos
    todos = [todo for todo in todos if todo.id != todo_id]
    return {"message": "Todo item deleted"} 

위의 코드에서는 Todo 항목을 생성, 조회 및 삭제할 수 있는 기본적인 REST API 엔드포인트를 제공합니다.

4. Docker 이해하기

Docker는 애플리케이션을 컨테이너로 패키징하고 배포할 수 있는 플랫폼입니다. 컨테이너는 애플리케이션과 그 의존성을 함께 묶어서 어디서든 동일하게 실행될 수 있도록 합니다. Docker를 사용하면 개발, 테스트, 배포 환경을 통일할 수 있으며, 이를 통해 일관성을 유지하고 배포를 용이하게 할 수 있습니다.

5. Dockerfile 작성 및 이미지 빌드

이제 FastAPI 애플리케이션을 Docker로 컨테이너화해 보겠습니다. Dockerfile을 작성하여 FastAPI 애플리케이션을 포함하는 이미지를 빌드할 수 있습니다.

Dockerfile 작성

FROM python:3.9

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt 파일에는 FastAPI와 Uvicorn이 포함되어 있어야 합니다.

fastapi
uvicorn

도커 이미지 빌드

이제 도커 이미지를 빌드합니다. 다음 명령어를 터미널에 입력합니다:

docker build -t fastapi-todo .

6. Docker 컨테이너 실행

도커 이미지가 성공적으로 빌드되었다면, 이를 기반으로 컨테이너를 실행할 수 있습니다. 다음 명령어를 입력하여 FastAPI 애플리케이션을 실행합니다:

docker run -d --name fastapi-todo -p 8000:8000 fastapi-todo

이제 웹 브라우저에서 http://localhost:8000/docs에 접속하여 Swagger UI를 통해 API를 테스트할 수 있습니다.

7. 결론 및 다음 단계

이번 강좌에서는 FastAPI를 사용하여 간단한 RESTful API를 개발하고, 이를 도커를 사용해 배포하는 방법에 대해 알아보았습니다. FastAPI는 성능이 뛰어나며 비동기 처리를 쉽게 만들 수 있기 때문에, 더욱 복잡한 애플리케이션 개발에도 적합합니다.

다음 단계로는 인증 및 권한 부여, 데이터베이스 통합 등의 기능을 추가하여 좀 더 발전된 RESTful API를 만들어 볼 수 있습니다. 이러한 추가 기능들은 FastAPI의 강력한 기능들을 활용하여 쉽게 구현할 수 있습니다.

참고: FastAPI 공식 문서에서 더 많은 예제와 정보를 찾아볼 수 있습니다.
FastAPI 공식 문서

FastAPI 서버개발, 스키마 – 요청, 요청의 정의

오늘 우리는 FastAPI 서버 개발 과정에서 매우 중요한 개념인 요청(Requests)과 스키마(Schema)에 대해 깊이 있게 탐구할 것입니다. FastAPI는 Python으로 작성된 웹 프레임워크로, API를 신속하게 구축하고 문서화하는데 최적화되어 있습니다. 우리의 목표는 기본적인 요청 처리부터 시작하여 요청 스키마를 정의하고 활용하는 방법까지 광범위하게 알아보는 것입니다.

1. FastAPI란?

FastAPI는 Python으로 작성된 현대적이고 빠른 웹 프레임워크로, RESTful API를 만드는 데 아주 적합합니다. Pydantic 최적화를 사용하여 신뢰성과 속도에서 매우 우수합니다. FastAPI는 자동으로 API 문서를 생성하는 Swagger UI와 ReDoc와 같은 도구들을 제공하여 개발자들이 보다 쉽게 작업할 수 있도록 돕습니다.

FastAPI의 주요 특징은 다음과 같습니다:

  • 고속 성능: Starlette와 Pydantic의 기반 위에 설계되어 빠릅니다.
  • 직관적인 코드 작성: 타입 힌트를 사용하여 코드의 가독성을 높입니다.
  • 자동 문서화: 요청 및 응답 스키마에 따라 자동으로 API 문서를 생성합니다.
  • 비동기 지원: 비동기 프로그래밍을 자연스럽게 지원합니다.

2. 요청(Request)과 응답(Response) 개념

웹 애플리케이션에서 클라이언트는 서버에 요청을 보내고, 서버는 클라이언트에게 응답을 보냅니다. 이 요청/응답 구조는 RESTful API의 핵심입니다.

요청은 크게 다음과 같이 분류될 수 있습니다:

  • GET 요청: 서버로부터 자원을 요청합니다.
  • POST 요청: 서버에 새로운 자원을 생성합니다.
  • PUT 요청: 서버에 존재하는 자원을 수정합니다.
  • DELETE 요청: 서버에서 자원을 삭제합니다.

3. FastAPI에서 요청 처리하기

FastAPI에서 클라이언트의 요청을 처리하기 위해서는 엔드포인트를 정의해야 합니다. 엔드포인트는 URL 경로와 HTTP 메서드(GET, POST 등)로 구성됩니다. 요청 처리를 위한 최소한의 FastAPI 코드 예시를 살펴보겠습니다:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

위의 코드에서 우리는 `/items/{item_id}` 경로에 대한 GET 요청을 처리하는 `read_item` 함수를 정의했습니다. {item_id}는 URL 경로의 동적 부분을 나타내며, 이를 통해 클라이언트로부터의 요청을 처리할 수 있습니다.

4. 요청 스키마(Request Schema)

FastAPI에서는 Pydantic을 사용하여 요청의 스키마를 정의할 수 있습니다. 스키마는 주어진 요청에서 어떤 데이터가 필요한지를 정의합니다. 이를 통해 데이터 유효성을 검증하고, 실수를 줄일 수 있습니다. 아래는 POST 요청에서 사용될 스키마를 정의하는 방법입니다:

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

이 코드는 Item이라는 데이터 모델을 정의합니다. 클라이언트가 요청을 보낼 때, name, description, price, tax와 같은 필드를 포함시키도록 요구합니다. 가격은 반드시 있어야 하며, 그 외의 필드는 선택 사항입니다.

5. 요청에서 스키마 활용하기

정의한 스키마를 FastAPI의 엔드포인트에서 사용할 수 있습니다. 아래의 예에서는 POST 요청을 통해 Item 객체를 받아들이는 엔드포인트를 정의합니다:

@app.post("/items/")
async def create_item(item: Item):
    return {"item_name": item.name, "item_price": item.price}

위의 코드는 클라이언트가 `/items/` 경로에 POST 요청을 보내면, Item 스키마에 맞는 데이터를 요구합니다. 데이터가 스키마를 만족하지 않으면 FastAPI는 자동으로 422 Unprocessable Entity 오류를 반환하게 됩니다.

6. 요청의 정의 및 유효성 검증

FastAPI와 Pydantic은 요청 데이터의 유효성을 자동으로 검증합니다. 예를 들어, 클라이언트가 잘못된 타입의 데이터를 보내면 FastAPI는 요청을 처리하기 전 에러 메시지를 반환합니다. 아래는 그 예입니다:

@app.post("/items/")
async def create_item(item: Item):
    return {"item_name": item.name, "item_price": item.price}

# 잘못된 요청 예시
# POST /items/ 
# { "name": "item_name", "price": "not_a_number" }

위와 같은 잘못된 요청이 들어오면 FastAPI는 잘못된 값을 검출하고, 다음과 같은 에러 메시지를 반환합니다:

{
  "detail": [
    {
      "loc": ["body", "price"],
      "msg": "value is not a valid float",
      "type": "value_error.float"
    }
  ]
}

7. 쿼리 파라미터와 경로 파라미터

FastAPI에서는 경로 파라미터와 쿼리 파라미터를 쉽게 사용할 수 있습니다. 경로 파라미터는 URL 경로의 일부분으로, 특정 리소스를 식별하는 데 사용됩니다. 한편, 쿼리 파라미터는 URL의 ? 뒤에 추가되며 필터링, 정렬 등의 기능을 수행할 수 있습니다.

예를 들어, 아래와 같이 쿼리 파라미터를 사용할 수 있습니다:

@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

이 엔드포인트를 호출하면 ?skip=5&limit=10과 같은 형식으로 요청할 수 있으며, 이에 따라 서버는 skip 및 limit 값을 사용하여 처리합니다.

8. 쿼리 파라미터와 요청 스키마 혼합하기

FastAPI에서는 요청 스키마와 쿼리 파라미터를 혼합하여 사용할 수 있습니다. 아래는 쿼리 파라미터와 스키마를 동시에 사용하는 예입니다:

@app.get("/items/")
async def read_item(item: Item, skip: int = 0):
    return {
        "item_name": item.name,
        "item_price": item.price,
        "skip": skip
    }

이 경우 클라이언트는 Body에 Item 객체를 포함시키고, 쿼리 파라미터로 skip 값을 추가하여 요청할 수 있습니다.

9. 요청의 문서화

FastAPI는 모든 엔드포인트 및 요청 스키마를 기반으로 자동으로 문서를 생성합니다. 이는 Swagger UI를 통해 확인할 수 있으며, 다음 경로로 접근할 수 있습니다:

위의 링크를 통해 API에 대한 자세한 정보를 확인할 수 있으며, 사용자 친화적인 인터페이스에서 각 엔드포인트를 테스트할 수도 있습니다.

10. 결론

FastAPI를 이용한 서버 개발 과정에서 요청의 정의와 스키마의 중요성을 확인하였습니다. 요청 스키마를 활용함으로써, 클라이언트와의 데이터 통신에서 발생할 수 있는 오류를 줄이고, 서버의 신뢰성을 높일 수 있습니다. 또한, 자동으로 생성되는 문서화 기능은 개발 효율성을 극대화해 줍니다.

FastAPI는 현대 웹 어플리케이션에 적합한 선택지입니다. 비동기 프로그래밍과 높은 성능을 더해, 여러분의 프로젝트에서 활용해보세요. 앞으로 더 많은 기능들과 예제를 다룰 예정이니, 계속 지켜봐 주세요!

FastAPI 서버개발, Alembic을 이용한 데이터베이스 마이그레이션 관리

1. 서론

FastAPI는 현대적이고 빠른 웹 프레임워크로, Python 3.6+의 타입 힌트를 활용하여 빠르고 직관적인 API를 구축할 수 있도록 도와줍니다. 아울러, 데이터베이스와의 상호작용에서 발생할 수 있는 다양한 상황을 효율적으로 처리하기 위해 Alembic과 같은 데이터베이스 마이그레이션 도구가 중요하니다. Alembic은 SQLAlchemy를 기반으로 하며, 여러분이 데이터베이스 스키마의 변경 사항을 관리하는 데 도움을 줍니다. 이 글에서는 FastAPI와 Alembic을 이용하여 데이터베이스 마이그레이션을 어떻게 처리하는지에 대해 자세히 살펴보겠습니다.

2. FastAPI와 Alembic 개요

FastAPI는 비동기적이고 경량화된 웹 서버를 구축할 수 있게 해주는 강력한 프레임워크입니다. RESTful API를 쉽게 발급할 수 있도록 설계되어 있으며, Swagger UI와 Redoc을 통해 자동으로 문서화를 지원합니다. 주로 SQLAlchemy ORM과 함께 사용되며, 데이터베이스와의 원활한 연결을 도와줍니다.

Alembic은 데이터베이스 마이그레이션을 관리하는 툴로, SQLAlchemy와 밀접한 관계를 가지고 있습니다. Alembic을 사용하면 데이터베이스 스키마 변경을 코드로 작성하고, 이를 통해 버전 관리를 할 수 있게 됩니다. 이를 통해 개발자는 데이터베이스 변화에 대한 관리를 더 쉽게 수행할 수 있습니다.

3. 개발 환경 구성

이제 FastAPI와 Alembic을 활용할 수 있는 개발 환경을 구성해 보겠습니다. 아래는 필요한 패키지 설치 방법입니다.

pip install fastapi[all] sqlalchemy alembic

위 명령어를 통해 FastAPI와 SQLAlchemy, Alembic을 설치합니다. 설치가 완료되면, 새로운 프로젝트 디렉토리를 생성하고 하위 디렉토리로 이동합니다.

mkdir fastapi-alembic-example
cd fastapi-alembic-example

이제 FastAPI 애플리케이션을 구성해보겠습니다.

4. FastAPI 애플리케이션 구성

FastAPI 애플리케이션을 위한 기본 구조를 만들어 봅시다. 다음 코드를 사용하여 main.py 파일을 생성합니다.

from fastapi import FastAPI
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "sqlite:///./test.db"

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

app = FastAPI()

# 데이터베이스 세션을 생성하기 위한 의존성
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/")
def read_root():
    return {"Hello": "World"}

위의 코드는 SQLite 데이터베이스에 연결하고 FastAPI 애플리케이션을 초기화합니다. 기본적인 “/” 엔드포인트를 통해 방문할 수 있는 간단한 환영 메시지를 반환합니다.

5. Alembic 설정

Alembic을 초기화해 보겠습니다. 아래 명령어로 Alembic 설정을 생성할 수 있습니다.

alembic init alembic

위 명령어를 실행하면, alembic이라는 디렉토리와 alembic.ini 파일이 생성됩니다. 이 파일에서 데이터베이스 URL을 설정해야 합니다.

[alembic]
script_location = alembic

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_sqlalchemy]
level = WARN
handlers = console
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers = console
qualname = alembic

[handler_console]
class = StreamHandler
args = []
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s - %(levelname)s - %(message)s

[alembic:app]
# DB에서 마이그레이션을 위한 FastAPI 데이터베이스 URL 설정
url = sqlite:///./test.db

6. 데이터베이스 모델 정의

이제 Alembic이 관리할 데이터베이스 모델을 정의합니다. 다음과 같이 models.py 파일을 생성하고 작성합니다.

from sqlalchemy import Column, Integer, String
from .database import 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)
    full_name = Column(String, index=True)
    disabled = Column(Boolean, default=False)

위와 같이 User 모델을 정의했으며, 이 모델은 사용자의 ID, 사용자 이름, 이메일, 전체 이름 및 비활성화 상태를 포함합니다.

7. 데이터베이스 마이그레이션 생성

Alembic을 사용하여 데이터베이스 마이그레이션을 생성해야 합니다. 다음 명령어를 통해 자동으로 마이그레이션 파일을 생성할 수 있습니다.

alembic revision --autogenerate -m "create users table"

위 명령어를 실행하면 alembic/versions 디렉토리에 새로운 마이그레이션 파일이 생성됩니다. 이 파일은 생성된 users 테이블에 대한 모든 변경 사항을 담고 있습니다.

8. 마이그레이션 적용

생성된 마이그레이션 파일을 데이터베이스에 적용하기 위해 아래와 같이 명령어를 실행합니다.

alembic upgrade head

위 명령어를 실행하면 데이터베이스에 users 테이블이 생성됩니다. 이 과정을 통해 Alembic이 데이터베이스 스키마를 관리하는데 필요한 기본적인 설정을 마쳤습니다.

9. FastAPI와 Alembic 연동

이제 FastAPI 애플리케이션에서 Alembic으로 만든 데이터베이스 모델을 연동해 보겠습니다. main.py 파일을 수정하여 사용자의 데이터를 처리하는 엔드포인트를 추가합니다.

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import models
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

@app.post("/users/", response_model=models.User)
def create_user(user: models.User, db: Session = Depends(get_db)):
    db.add(user)
    db.commit()
    db.refresh(user)
    return user

위 코드를 통해 /users/ 엔드포인트가 생성되어 사용자를 추가할 수 있게 되었습니다.

10. 결론

FastAPI와 Alembic을 통합하여 데이터베이스 마이그레이션을 관리하는 방법에 대해 알아보았습니다. 이 과정에서 FastAPI의 기본적인 설정과 Alembic을 통한 DB 마이그레이션이 어떻게 이루어지는지 살펴보았습니다. 이러한 방식을 통해 여러분의 웹 애플리케이션에서 데이터베이스 변경 사항을 보다 효과적으로 관리할 수 있을 것입니다.

11. 참고 자료