FastAPI 서버개발, 패스워드 해싱

현대 웹 애플리케이션에서 사용자 인증 및 보안을 확보하는 것은 매우 중요한 문제입니다. 특히, 비밀번호와 같은 민감한 정보는 적절하게 보호되어야 합니다. 이를 위해 우리는 FastAPI를 사용하여 백엔드 서버를 개발하고, 비밀번호 해싱을 통해 사용자 비밀번호를 안전하게 저장하는 방법을 알아보겠습니다.

1. FastAPI 소개

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 비동기 프로그래밍을 지원하고, OpenAPI 및 JSON Schema를 자동으로 생성할 수 있습니다. 성능이 뛰어나며, 신속한 프로토타이핑과 설계 검증에 적합합니다. FastAPI는 RESTful API 개발을 위한 매우 직관적이고 간편한 접근 방식을 제공합니다.

2. 패스워드 해싱이란?

패스워드 해싱은 사용자가 입력한 비밀번호를 해시 함수를 통해 변형해 저장하는 작업입니다. 이를 통해 비밀번호가 노출되더라도 원래 비밀번호를 알아낼 수 없도록 방지할 수 있습니다. 해싱 알고리즘으로는 BCrypt, Argon2, PBKDF2 등이 있으며, 이들 각각은 복잡성과 보안 수준이 다릅니다.

2.1 해싱 알고리즘

비밀번호 해싱에서 가장 널리 사용되는 알고리즘은 다음과 같습니다:

  • BCrypt: 비밀번호를 해싱할 때 적절한 비용 인자를 사용하여 보안을 강화하는 알고리즘입니다.
  • Argon2: 2015년 패스워드 해싱 대회에서 우승한 알고리즘으로, 메모리 요구 사항을 증가시켜 공격에 대한 저항력을 높입니다.
  • PBKDF2: 반복적 해싱을 통해 비밀번호의 복잡성을 높이는 알고리즘으로, 일정량의 시간과 메모리를 소모하도록 설계되었습니다.

3. FastAPI 환경 구축

이제 FastAPI 프로젝트를 설정하고 비밀번호를 안전하게 해싱하기 위한 준비를 해보겠습니다.

3.1 FastAPI 설치

FastAPI 및 해싱을 위한 필요한 라이브러리를 설치합니다. 다음 명령어를 실행하여 필요한 패키지를 설치합니다:

pip install fastapi uvicorn passlib[bcrypt]

3.2 프로젝트 구조

다음과 같은 디렉토리 구조를 생성합니다:


project/
│
├── app/
│   ├── __init__.py
│   ├── main.py
│   └── models.py
└── requirements.txt
    

3.3 기본 FastAPI 앱 작성

이제 FastAPI 애플리케이션을 작성해보겠습니다. main.py 파일에 기본 API를 설정합니다.


from fastapi import FastAPI
from pydantic import BaseModel
from passlib.context import CryptContext

app = FastAPI()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 사용자 모델 정의
class User(BaseModel):
    username: str
    password: str

# 비밀번호 해싱 함수
def hash_password(password: str) -> str:
    return pwd_context.hash(password)

# 사용자 등록 엔드포인트
@app.post("/register/")
async def register(user: User):
    hashed_password = hash_password(user.password)
    return {"username": user.username, "hashed_password": hashed_password}
    

4. 비밀번호 해싱 구현

위 코드에서는 비밀번호 해싱을 위한 간단한 FastAPI 애플리케이션을 작성하였습니다. 이 애플리케이션은 사용자가 등록할 때 비밀번호를 해싱하여 반환합니다.

4.1 비밀번호 해싱 과정 설명

  • 사용자가 등록하면, register 엔드포인트가 호출됩니다.
  • 입력받은 비밀번호는 hash_password 함수를 통해 해싱됩니다.
  • 해싱된 비밀번호는 JSON 응답으로 반환됩니다.

5. 서버 실행하기

FastAPI 서버를 실행하기 위해 터미널에서 다음 명령어를 입력합니다:

uvicorn app.main:app --reload

서버가 성공적으로 실행되면, http://127.0.0.1:8000/docs를 방문하여 Swagger UI에서 API를 테스트할 수 있습니다.

6. 비밀번호 검증

사용자가 로그인하면, 입력한 비밀번호와 DB에 저장된 해싱된 비밀번호를 비교해야 합니다. 이를 위해 비밀번호 검증 함수를 추가해 보겠습니다.


# 비밀번호 검증 함수
def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

@app.post("/login/")
async def login(user: User):
    # 비밀번호 검증 로직 (여기서는 간단히 하드코딩)
    stored_hashed_password = "$2b$12$KixR7Pq2B7lZq5NOsx.xreOS5Jz4P3qv1E8pF8ozFpXZKLaMvvWry"  # 예시 해시
    if verify_password(user.password, stored_hashed_password):
        return {"message": f"Welcome {user.username}"}
    else:
        return {"message": "Invalid credentials"}
    

7. 결론

이번 글에서는 FastAPI로 간단한 백엔드 서버를 구성하고 패스워드 해싱 기능을 추가하는 방법을 배웠습니다. 비밀번호는 해싱을 통해 저장함으로써 사용자의 정보를 안전하게 보호할 수 있습니다. 본 예제는 간단한 형태이므로, 실제 서비스에서는 데이터베이스와의 연동, 에러 처리, 유효성 검증 등 추가적인 로직이 필요합니다.

8. 추가 자료

FastAPI 및 패스워드 해싱 관련 추가 자료를 아래와 같이 추천합니다:

FastAPI를 통해 성능 좋고 안전한 웹 API를 구축해 보세요!

© 2023 FastAPI 개발 강좌. All rights reserved.

FastAPI 서버개발, Jinja, 매크로

FastAPI는 최신 웹 프레임워크로, 비동기 프로그래밍과 타입 힌트를 지원하여 빠른 성능과 개발 편의성을 제공합니다. 본 강좌에서는 FastAPI를 사용한 서버 개발의 기초부터 Jinja2를 사용한 템플릿 렌더링, 그리고 매크로를 사용한 템플릿의 재사용성 향상까지 알아보겠습니다.

1. FastAPI 소개

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 다음과 같은 특징이 있습니다:

  • 신속한 개발
  • 자동 문서화
  • 비동기 요청 처리
  • 타입 검사

FastAPI는 Starlette 프레임워크를 기반으로 하며, Pydantic을 통해 데이터 유효성 검사를 수행합니다. 이러한 특성 덕분에 FastAPI는 RESTful API 개발에 매우 적합합니다.

2. 개발 환경 설정

FastAPI를 사용하기 위해 먼저 Python과 FastAPI를 설치해야 합니다. 아래 명령어로 설치할 수 있습니다:

pip install fastapi uvicorn

추가로 Jinja2 템플릿 엔진도 설치해야 합니다:

pip install jinja2

3. FastAPI 기본 예제

다음은 간단한 FastAPI 서버 예제입니다. 이 서버는 기본적인 GET 및 POST 요청을 처리합니다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 데이터 모델 정의
class Item(BaseModel):
    name: str
    price: float
    is_offer: bool = None

# GET 요청 처리
@app.get("/")
async def read_root():
    return {"Hello": "World"}

# POST 요청 처리
@app.post("/items/")
async def create_item(item: Item):
    return item

위 코드를 사용하여 FastAPI 서버를 실행하려면, 다음 명령어를 입력합니다:

uvicorn main:app --reload

이제 localhost:8000에서 서버가 실행되고 있습니다.

4. Jinja2 템플릿 엔진

Jinja2는 Python으로 작성된 템플릿 엔진으로, 파이썬 코드를 HTML 문서에 쉽게 삽입할 수 있도록 해줍니다. FastAPI와 Jinja2를 결합하면 동적인 웹 페이지를 만들 수 있습니다.

4.1 Jinja2 설치

Jinja2는 이미 설치한 상태로 가정하겠습니다. 만약 설치하지 않았다면, 이전 단락의 명령어를 통해 설치하시면 됩니다.

4.2 Jinja2 템플릿 설정

FastAPI와 Jinja2를 연동하기 위해, 다음과 같은 디렉토리 구조를 설정합니다:

project/
│
├── main.py
└── templates/
    └── index.html

이제 index.html 파일을 작성해보겠습니다:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FastAPI & Jinja2</title>
</head>
<body>
    <h1>환영합니다!</h1>
    <p>여기는 FastAPI와 Jinja2로 작성된 웹 페이지입니다.</p>
    <ul>
    {% for item in items %}
        <li>{{ item.name }}: ${{ item.price }}{% if item.is_offer %} (할인 중){% endif %}</li>
    {% endfor %}
    </ul>
</body>
</html>

4.3 FastAPI에서 Jinja2 템플릿 사용하기

이제 FastAPI에서 Jinja2를 사용하여 템플릿을 렌더링할 수 있습니다. 다음과 같은 코드를 main.py에 추가합니다:

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

templates = Jinja2Templates(directory="templates")

@app.get("/items/", response_class=HTMLResponse)
async def read_items(request: Request):
    items = [{"name": "Item 1", "price": 10.5, "is_offer": True},
             {"name": "Item 2", "price": 20.5, "is_offer": False}]
    return templates.TemplateResponse("index.html", {"request": request, "items": items})

이제 localhost:8000/items/로 이동하면, Jinja2 템플릿을 통해 렌더링된 HTML 페이지를 확인할 수 있습니다.

5. Jinja2 매크로 사용하기

매크로는 Jinja2의 강력한 기능으로, 템플릿 내에서 코드의 재사용성을 높여줍니다. 매크로를 사용하면 반복되는 코드 패턴을 간편하게 정의하고 재사용할 수 있습니다.

5.1 매크로 정의

먼저 index.html 파일에 매크로를 추가해보겠습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FastAPI & Jinja2</title>
</head>
<body>
    <h1>환영합니다!</h1>

    <!-- 매크로 정의 -->
    <{% macro render_item(item) %}>
        <li>{{ item.name }}: ${{ item.price }}{% if item.is_offer %} (할인 중){% endif %}</li>
    <{% endmacro %}>

    <ul>
    {% for item in items %}
        {{ render_item(item) }}
    {% endfor %}
    </ul>
</body>
</html>

5.2 매크로 사용하기

이제 매크로를 정의했으므로, render_item 매크로를 호출하여 각 아이템을 렌더링할 수 있습니다. 앞서 작성했던 read_items 함수는 그대로 유지됩니다.

이렇게 작성한 후, localhost:8000/items/에 접속하면 매크로를 통해 렌더링된 결과를 확인할 수 있습니다.

6. 마치며

이번 강좌에서는 FastAPI를 사용한 웹 서버 개발 방법과 Jinja2 템플릿 엔진 사용법, 그리고 매크로를 통한 코드 재사용성을 높이는 방법에 대해 알아보았습니다. FastAPI는 성능뿐만 아니라 생산성을 높여주는 훌륭한 도구입니다. 이를 통해 여러분의 웹 애플리케이션을 더욱 빠르고 효율적으로 개발할 수 있기를 바랍니다.

추가적으로 FastAPI와 Jinja2에 대한 더 많은 예제 및 유용한 자료는 공식 문서에서 확인하실 수 있습니다.

참고 자료

FastAPI 서버개발, FastAPI 자동 문서화

FastAPI는 현대적인 웹 애플리케이션을 구축하기 위한 높은 성능을 자랑하는 Python 웹 프레임워크입니다. FastAPI의 가장 큰 장점 중 하나는
자동화된 API 문서화인데, 이는 개발자들이 API를 쉽게 이해하고 사용할 수 있도록 해줍니다. 이 글에서는 FastAPI의 문서화 기능과 그 사용 방법에 대해
자세히 설명하겠습니다.

FastAPI 소개

FastAPI는 Starlette를 기반으로 하여 만들어진 프레임워크로, asyncio를 지원하여 비동기적인 요청 처리가 가능하며, 매우 높은 성능을 자랑합니다.
FastAPI는 데이터 검증, 직렬화, 문서화 등의 기능을 쉽게 구현할 수 있도록 도와줍니다. 또한, FastAPI를 사용하면 Python 타입 힌트를 활용하여 API의 입력 및 출력
모델을 정의하고, 이를 기반으로 자동으로 문서를 생성할 수 있습니다.

FastAPI의 기본적인 사용법

FastAPI를 사용하기 위해서는 먼저 FastAPI 라이브러리를 설치해야 합니다. 아래와 같은 명령어로 설치할 수 있습니다:

pip install fastapi[all]

FastAPI의 기본적인 사용법을 알아보겠습니다. 아래는 아주 간단한 FastAPI 앱의 예시입니다.

from fastapi import FastAPI

app = FastAPI()

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

위의 코드에서 FastAPI() 인스턴스를 생성하고, @app.get("/")를 사용하여 루트 경로에 대한 GET 요청을 처리하는
read_root 함수를 정의했습니다. FastAPI는 이 함수를 호출할 때 자동으로 JSON 응답을 반환합니다.

FastAPI의 자동 문서화 기능

FastAPI의 자동 문서화 기능은 기본적으로 Swagger UI와 ReDoc을 제공합니다. FastAPI 앱이 실행되는 동안 다음 URL에서 문서화된 API를 확인할 수 있습니다:

  • Swagger UI: http:///docs
  • ReDoc: http:///redoc

FastAPI는 각 엔드포인트에 대한 문서를 자동으로 생성하며, Swagger UI는 이를 시각적으로 표현합니다.
문서를 구성하는 데 있어서 FastAPI의 장점은 Python 타입 힌트를 이용해 API의 요청 및 응답 모델을 정의할 수 있다는 점입니다.

요청 및 응답 모델 정의

FastAPI에서는 Pydantic을 사용하여 데이터 모델을 정의할 수 있습니다. Pydantic은 데이터 검증과 설정을 위한 데이터 클래스와 검증 기능을 제공합니다.
요청 및 응답 모델을 정의하면 FastAPI는 이를 이용해 자동으로 문서를 생성합니다. 아래는 요청 모델과 응답 모델을 사용하는 예제입니다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

@app.post("/items/", response_model=Item)
def create_item(item: Item):
    return item

위의 코드에서 Item 클래스를 정의하여 요청 모델을 만들었습니다. 이 클래스는 BaseModel을 상속하며
각 필드에 대한 데이터 타입을 정의합니다. @app.post("/items/")를 사용하여 POST 요청을 처리하는
create_item 함수를 정의하고, 이 함수는 요청에서 Item 모델을 인자로 받습니다. 또한, 응답 모델로도 같은
Item 클래스를 사용하고 있습니다.

FastAPI에서의 문서화 항목 설명

FastAPI 자동 문서화에는 몇 가지 유용한 기능이 포함되어 있습니다. 이 섹션에서는 몇 가지 주요 기능에 대해 살펴보겠습니다.

요청 본문 설명

FastAPI는 Pydantic의 모델을 사용하여 API 요청의 본문을 설명합니다. 위의 예제에서는 Item 모델이 요청 본문에 대한
구조를 설명하므로, Swagger UI에서 해당 요청의 구조를 쉽게 이해할 수 있습니다.

쿼리 매개변수 설명

FastAPI는 쿼리 매개변수에 대한 설명도 추가할 수 있습니다. 예를 들어, 아래와 같이 쿼리 매개변수를 사용하는 API를 만들어 보겠습니다.

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

위의 코드에서 skiplimit 매개변수를 정의하였고, 기본값을 설정했습니다. FastAPI는 이 정보에 기반하여
Swagger UI에서 쿼리 매개변수에 대한 설명을 제공합니다.

답변 설명 추가

FastAPI는 응답 타입에 대한 설명도 추가할 수 있습니다. 응답 모델을 정의할 때 response_model 매개변수를 사용하여
명확하게 응답의 구조를 설명할 수 있습니다.

FastAPI 사용자 지정 문서화

기본적으로 FastAPI는 Swagger와 ReDoc을 사용하여 자동 문서화를 제공합니다. 그러나 때때로 사용자 지정 내용을 추가하고 싶을 수 있습니다.
FastAPI는 엔드포인트에 대한 설명 및 태그를 사용자 지정할 수 있는 방법을 제공합니다.

엔드포인트에 대한 설명 추가

FastAPI의 경로에 대한 설명과 설명을 추가할 수 있습니다. 아래는 이를 보여주는 예제입니다.

@app.get("/items/", tags=["items"], summary="Get items", description="Retrieve a list of items based on skip and limit")
def read_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

위의 코드에서 tags, summary, 및 description 매개변수를 사용하여 Swagger UI에서
더 나은 설명을 제공합니다. 이는 다른 개발자들이 API를 이해하는 데 큰 도움이 됩니다.

결론

FastAPI는 Python 기반의 API 서버를 쉽고 빠르게 구축할 수 있게 해주는 프레임워크입니다. 자동 문서화 기능을 통해 Swagger UI 및
ReDoc을 제공하여 API의 사용을 훨씬 간편하게 만들어 줍니다. Pydantic을 활용하여 데이터 모델을 정의하고, 이를 기반으로
요청 및 응답을 담당하는 API를 작성할 수 있습니다. 사용자 지정 문서화 기능을 통해 더 나은 API 문서를 작성할 수 있으며, 다른
개발자들과의 협업을 용이하게 할 수 있습니다.

FastAPI의 이러한 특성 덕분에 빠르고 효율적인 백엔드 서버 개발이 가능합니다. 이는 특히 데이터 중심의 애플리케이션을 개발할
때 큰 장점을 제공합니다.

FastAPI 서버개발, pydantic 모델을 사용한 요청 바디 검증

FastAPI는 Python으로 웹 API를 구축할 때 매우 인기가 높은 프레임워크입니다. FastAPI의 가장 큰 장점 중 하나는 Pydantic을 이용한 데이터 검증입니다. Pydantic은 강력한 데이터 검증 및 설정 관리 도구로, Python의 타입 힌팅을 활용하여 데이터를 검증하고 직렬화하는 기능을 제공합니다.

1. FastAPI 소개

FastAPI는 빠른 API 구축을 목표로 설계된 Python 웹 프레임워크이며, 성능과 생산성을 모두 고려하여 만들어졌습니다. 성능적으로는 Node.js와 Go에 근접하며, 쉬운 사용성을 가지고 있어 API 개발을 빠르게 진행할 수 있습니다.

1.1 주요 특징

  • 빠른 성능: Starlette와 Pydantic을 기반으로 한 비동기 처리를 지원합니다.
  • 자동 문서화: OpenAPI와 JSON Schema를 기반으로 하는 자동화된 API 문서화를 지원합니다.
  • 타입 힌팅: Python 3.6 이상의 버전을 활용하여 코드 가독성을 높이고, 데이터 검증을 용이하게 합니다.

2. Pydantic을 사용한 요청 바디 검증

FastAPI에서 요청 바디를 검증하는 가장 흔한 방법은 Pydantic 모델을 사용하는 것입니다. Pydantic 모델은 Python 클래스처럼 정의되며, 클래스의 속성은 필드와 그에 대한 타입 힌트를 제공합니다. 이를 통해 API의 요청 데이터를 검증할 수 있습니다.

2.1 Pydantic 모델 정의

Pydantic 모델을 정의하는 기본 형식은 다음과 같습니다.


from pydantic import BaseModel

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

위 코드는 사용자의 정보를 담고 있는 User 모델을 정의합니다. 각 속성은 그에 해당하는 데이터 타입을 명시하고 있습니다. Pydantic은 이 모델을 기반으로 데이터의 유효성을 검사합니다.

2.2 FastAPI와 Pydantic 모델의 통합

FastAPI에서는 경로 운영체제의 매개변수로 Pydantic 모델을 바로 사용할 수 있습니다. 예를 들어, 클라이언트가 보낸 JSON 요청을 User 모델로 검증할 수 있습니다.


from fastapi import FastAPI

app = FastAPI()

@app.post("/users/")
async def create_user(user: User):
    return {"user_id": user.id, "name": user.name}

위 코드에서 /users/ 경로에 대한 POST 요청이 오면, FastAPI는 JSON 요청 본문을 User 모델 인스턴스로 변환하고 검증합니다. 데이터가 유효하면, 해당 데이터가 user 매개변수로 전달됩니다.

2.3 필드 검증

Pydantic은 필드 검증을 위한 여러 기능을 제공합니다. 예를 들어, 필드에 대한 제약조건이나 검증 로직을 추가할 수 있습니다.


from pydantic import EmailStr, conint

class User(BaseModel):
    id: conint(ge=1)  # 1 이상의 정수만 허용
    name: str
    email: EmailStr  # 유효한 이메일 형식
    age: conint(ge=0)  # 0 이상의 정수로 유효성 검사

여기서 conintEmailStr은 각각 정수 범위와 이메일 형식의 유효성을 검사합니다. 이런 제약조건을 통해 잘못된 입력을 사전에 차단할 수 있습니다.

3. 요청 바디 검증의 실제 예제

아래는 FastAPI와 Pydantic 모델을 사용하여 간단한 사용자 관리 API를 구현한 예입니다. 이 예제에서는 사용자의 정보를 생성하고, 조회하는 API를 구현합니다.


from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, conint
from typing import List

app = FastAPI()

class User(BaseModel):
    id: conint(ge=1)
    name: str
    email: EmailStr
    age: conint(ge=0)

# 메모리에 사용자 데이터를 저장할 리스트
users_db = []

@app.post("/users/")
async def create_user(user: User):
    users_db.append(user)
    return {"user_id": user.id, "name": user.name}

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

이 API는 다음과 같은 기능을 제공합니다:

  • POST /users/: 새로운 사용자를 생성합니다. Pydantic 모델을 통해 요청 바디의 유효성을 검증합니다.
  • GET /users/: 현재 등록된 사용자 목록을 조회합니다. 저장된 사용자 데이터를 반환합니다.

3.1 API 테스트

FastAPI는 Swagger UI를 통해 API를 쉽게 테스트할 수 있는 기능을 제공합니다. 서버를 실행한 후 http://127.0.0.1:8000/docs에 접속하면, 시각적으로 API를 테스트할 수 있는 인터페이스가 제공됩니다.

uvicorn main:app --reload

위 명령어로 FastAPI 서버를 실행한 후, 브라우저에서 Swagger UI에 접속해보세요. API 엔드포인트를 클릭하고, 요청에 대한 데이터를 입력하여 테스트할 수 있습니다.

3.2 오류 처리

Pydantic은 모델 객체 생성 시 오류를 감지하고, 자동으로 HTTPException을 발생시킵니다. 예를 들어, 유효하지 않은 이메일 주소를 입력하면 FastAPI는 자동으로 422 Unprocessable Entity 상태 코드를 반환합니다.


@app.post("/users/")
async def create_user(user: User):
    if user.age < 18:
        raise HTTPException(status_code=400, detail="Must be at least 18.")
    users_db.append(user)
    return {"user_id": user.id, "name": user.name}

위의 예시는 사용자 나이가 18세 미만일 경우 에러를 발생시키는 예입니다. 이렇게 FastAPI와 Pydantic은 함께 사용자 정의 예외 처리를 간편하게 구현할 수 있습니다.

4. 결론

FastAPI는 Pydantic을 활용하여 요청 바디에 대한 검증을 쉽게 처리할 수 있는 강력한 프레임워크입니다. 데이터 타입, 제약 조건, 이메일 형식 검증 등 다양한 검증 기능을 제공하며, 이를 통해 API 개발 과정에서 발생할 수 있는 오류를 사전에 방지할 수 있습니다. FastAPI와 Pydantic을 활용하여 시의적절하게 API를 구축하는 연습을 진행한다면, 실제 프로젝트에 큰 도움이 될 것입니다.

이 글이 FastAPI와 Pydantic을 사용하는 데 도움이 되기를 바랍니다. Now, it’s your turn to dive in and start building!

FastAPI 서버개발, 도커 이미지 배포

현대 웹 애플리케이션 개발에서 API 서버는 핵심적인 역할을 하고 있습니다. 그 중 FastAPI는 비동기 프로그래밍을 지원하며, 높은 성능과 사용자 친화적인 문서를 자동 생성하는 강력한 웹 프레임워크입니다. 본 강좌에서는 FastAPI를 이용한 서버 개발 방법과 이를 도커 이미지로 배포하는 방법에 대해 자세히 설명하겠습니다.

1. FastAPI란?

FastAPI는 Python 3.6 이상에서 사용할 수 있는 현대적인 웹 프레임워크입니다. FastAPI의 주요 특징은 다음과 같습니다:

  • 비동기 지원: Python에서 비동기 프로그래밍을 쉽게 사용할 수 있도록 지원합니다.
  • 자동 문서화: Swagger UI와 ReDoc을 통한 자동 API 문서화를 제공합니다.
  • 타입 힌트: Python 타입 힌트를 통해 코드 작성 시 더 많은 정보를 제공합니다.
  • 설정 간결성: 매우 간결하고 직관적인 API 설계를 지원합니다.

2. FastAPI 설치

FastAPI를 사용하기 위해서는 우선 Python과 FastAPI 패키지를 설치해야 합니다. 다음 명령어를 사용해 설치할 수 있습니다:

pip install fastapi uvicorn

3. 기본 FastAPI 서버 만들기

간단한 FastAPI 서버를 만들어 보겠습니다. 아래 코드는 기본적인 RESTful API의 구조를 보여줍니다.

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, query_param: str = None):
    return {"item_id": item_id, "query_param": query_param}

위 코드를 작성한 후, Uvicorn을 통해 서버를 실행할 수 있습니다:

uvicorn main:app --reload

이제 브라우저에서 http://127.0.0.1:8000 으로 이동하면 “Hello World” 메시지를 확인할 수 있습니다. 또한 Swagger UI에서 API 문서를 확인할 수 있습니다.

4. FastAPI를 이용한 데이터베이스 연결

FastAPI와 데이터베이스를 연결하여 더 복잡한 애플리케이션을 구축할 수 있습니다. 예를 들어, SQLAlchemy를 사용해 데이터베이스와 연결해봅시다. 먼저 필요한 패키지를 설치합니다.

pip install sqlalchemy databases

다음으로, 간단한 데이터베이스 모델을 정의합니다:

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

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

engine = create_engine(DATABASE_URL)
Base = declarative_base()

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    description = Column(String, index=True)

Base.metadata.create_all(bind=engine)

5. FastAPI와 SQLAlchemy를 통한 CRUD API 생성

이제 CRUD(Create, Read, Update, Delete) 작업을 수행하는 API를 작성해보겠습니다. 아래의 코드는 Item 모델을 사용하여 CRUD 기능을 구현합니다.

from fastapi import FastAPI, HTTPException
from sqlalchemy.orm import Session
from .database import engine, SessionLocal
from .models import Item  # 위에서 정의한 모델

app = FastAPI()

# Dependency
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.post("/items/")
async def create_item(item: Item, db: Session = next(get_db())):
    db.add(item)
    db.commit()
    db.refresh(item)
    return item

@app.get("/items/{item_id}")
async def read_item(item_id: int, db: Session = next(get_db())):
    return db.query(Item).filter(Item.id == item_id).first()

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, db: Session = next(get_db())):
    db_item = db.query(Item).filter(Item.id == item_id).first()
    if db_item is None:
        raise HTTPException(status_code=404, detail="Item not found")
    
    db_item.name = item.name
    db_item.description = item.description
    db.commit()
    return db_item

@app.delete("/items/{item_id}")
async def delete_item(item_id: int, db: Session = next(get_db())):
    db_item = db.query(Item).filter(Item.id == item_id).first()
    if db_item is None:
        raise HTTPException(status_code=404, detail="Item not found")
    
    db.delete(db_item)
    db.commit()
    return {"detail": "Item deleted successfully"}

6. FastAPI 애플리케이션 도커화

다 작성한 API 서버를 도커화를 통해 배포할 수 있습니다. 이를 위해서는 도커파일을 작성해야 합니다. 아래는 프로젝트 루트 디렉토리에 위치할 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", "--reload"]

위의 Dockerfile은 Python 이미지 기반으로 하며, 필요한 패키지를 설치하고 애플리케이션 코드를 복사하여 Uvicorn으로 서버를 실행합니다.

7. Docker Compose 사용하기

복잡한 애플리케이션을 위해 Docker Compose를 설정해보겠습니다. ‘docker-compose.yml’ 파일을 생성하고 아래와 같이 작성해주세요:

version: '3'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - .:/app
    environment:
      - DATABASE_URL=sqlite:///./test.db

이제 다음 명령어로 도커 이미지를 빌드하고 실행할 수 있습니다:

docker-compose up --build

이를 통해 FastAPI 서버가 도커에서 실행되며, http://localhost:8000에서 접근 가능합니다.

8. 종합

FastAPI와 Docker를 이용한 웹 애플리케이션 개발은 매우 효율적이며, 높은 성능과 쉬운 배포가 장점입니다. 이번 강좌를 통해 FastAPI와 Docker 사용의 기초를 배우셨다면, 더 복잡한 애플리케이션에 도전해 보시기 바랍니다. 데이터베이스 연결, 인증 및 권한 관리, 데이터 검증 등 다양한 기능을 추가하여 더욱 강력한 API를 개발할 수 있습니다.

9. 추가 자료

FastAPI와 관련하여 자세한 문서는 공식 웹사이트(fastapi.tiangolo.com)에서 확인할 수 있으며, 커뮤니티에서 제공하는 다양한 자료와 예제를 참고해 보세요. Docker에 관한 문서는 Docker 공식 홈페이지(docs.docker.com)에서 찾아볼 수 있습니다.

이 글이 FastAPI와 Docker에 대한 이해를 깊이 있게 하는 데 도움이 되기를 바랍니다. Happy Coding!