FastAPI 서버개발, Uvicorn으로 FastAPI 서버 실행하기

현대 웹 개발에서 효율성과 성능은 매우 중요합니다. 특히 백엔드 개발에서 이러한 요소들은 더욱 중요해지고 있습니다. FastAPI는 이러한 요구를 충족시키기 위해 설계된 Python 웹 프레임워크입니다. FastAPI는 비동기 프로그래밍을 지원하며, 빠른 API 개발을 위해 다양한 기능을 제공합니다. 이 글에서는 FastAPI를 사용하여 서버를 구축하고, Uvicorn을 사용하여 이를 실행하는 방법을 자세히 살펴보겠습니다.

1. FastAPI란?

FastAPI는 Python으로 작성된 최신 웹 프레임워크입니다. 그 주요 특징은 다음과 같습니다:

  • 비동기 지원: FastAPI는 비동기 프로그래밍을 지원하여 높은 성능을 구현할 수 있습니다.
  • 자동 문서화: FastAPI는 Swagger UI와 Redoc과 같은 자동 문서화 기능을 제공합니다.
  • 타입 힌트: Python의 타입 힌트를 기반으로 API의 데이터 모델과 유효성 검사를 자동으로 처리합니다.
  • 성능: Starlette와 Pydantic을 기반으로 구축되어 있어 매우 빠른 속도를 자랑합니다.

2. Uvicorn이란?

Uvicorn은 ASGI(Asynchronous Server Gateway Interface) 서버입니다. FastAPI와 같은 비동기 웹 프레임워크를 실행하기 위한 경량 웹 서버로, 다양한 비동기 처리를 지원합니다. FastAPI와 함께 사용할 때, 다음과 같은 장점이 있습니다:

  • 높은 성능: Uvicorn은 비동기 IO를 활용하여 요청을 처리할 수 있으므로 매우 빠릅니다.
  • 간단한 사용법: 명령어로 쉽게 서버를 실행할 수 있습니다.
  • 적은 자원 소모: 가벼운 서버이기 때문에 소모하는 자원이 적습니다.

3. FastAPI 설치하기

FastAPI를 설치하기 위해서는 Python이 설치되어 있어야 합니다. Python이 설치된 후, 다음의 명령어를 사용하여 FastAPI와 Uvicorn을 설치할 수 있습니다:

pip install fastapi uvicorn

4. FastAPI 기본 설정

설치가 완료되면, FastAPI를 이용하여 간단한 API 서버를 구축해보겠습니다. 아래는 기본적인 FastAPI 설정을 보여주는 코드 예제입니다:

from fastapi import FastAPI
    
app = FastAPI()

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

5. Uvicorn으로 FastAPI 서버 실행하기

FastAPI 애플리케이션을 실행하기 위해 Uvicorn을 사용할 수 있습니다. 위에서 작성한 코드를 main.py라는 파일에 저장한 후, 다음의 명령어로 Uvicorn 서버를 실행할 수 있습니다:

uvicorn main:app --reload

여기서 main은 파일 이름이고, app는 FastAPI 인스턴스의 이름입니다. --reload 플래그는 코드 변경 시 자동으로 서버를 다시 시작해줍니다.

5.1 실행 결과 확인하기

서버가 성공적으로 실행되면, 브라우저를 열고 http://127.0.0.1:8000에 접속하여 결과를 확인할 수 있습니다. JSON 형태로 {“message”: “Hello, FastAPI!”}가 출력됩니다. 또한, Swagger UI를 통해 API 문서에 접근할 수 있습니다. 주소는 http://127.0.0.1:8000/docs입니다.

6. FastAPI의 경로 매개변수

FastAPI는 경로 매개변수를 통해 URL의 일부를 변수로 사용할 수 있게 해줍니다. 예를 들어 사용자의 이름을 포함하는 간단한 API를 작성해보겠습니다:

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    return {"user_id": user_id}

위의 예제에서 user_id는 URL 경로에서 동적으로 추출되는 값입니다. 서버를 실행한 후 http://127.0.0.1:8000/users/1와 같은 경로에 접속하면 {"user_id": 1}와 같은 결과를 확인할 수 있습니다.

7. FastAPI의 쿼리 매개변수

쿼리 매개변수 역시 FastAPI에서 쉽게 처리할 수 있습니다. 다음은 쿼리 매개변수를 사용하는 예제입니다:

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

이 API에 접속하면서 쿼리 매개변수를 전달하면, 예를 들어 http://127.0.0.1:8000/items/?q=test로 접근 시 {"query": "test"}라는 결과를 반환합니다.

8. FastAPI에서 POST 요청 처리하기

FastAPI는 POST 요청을 통해 클라이언트로부터 데이터를 받을 수 있습니다. 아래는 JSON 형식의 요청 데이터를 처리하는 예제입니다:

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    is_offer: bool = None

@app.post("/items/")
async def create_item(item: Item):
    return item

위와 같은 방식으로 POST 요청을 보내면, 전송된 데이터를 그대로 반환하는 API를 만들 수 있습니다. 예를 들어 요청을 보내는 방법은 다음과 같습니다:

import requests

response = requests.post("http://127.0.0.1:8000/items/", json={"name": "test", "price": 42.0})
print(response.json())

9. FastAPI와 데이터베이스 연동

FastAPI는 SQLAlchemy와 같은 ORM(Object Relational Mapping) 라이브러리와 함께 사용할 수 있습니다. 데이터베이스와의 연동을 통해 실제 데이터를 저장하고 불러오는 작업을 수행할 수 있습니다.

다음은 간단한 SQLAlchemy와 FastAPI를 연동한 코드 예제입니다:

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)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)

Base.metadata.create_all(bind=engine)

위의 코드는 SQLite 데이터베이스를 생성하고 users 테이블을 설정하는 작업을 수행합니다. FastAPI와 함께 데이터를 입력하고 조회하는 API를 작성할 수 있습니다.

10. 비동기 처리

FastAPI는 비동기 처리를 지원하므로, 예를 들어 여러 API를 동시에 호출해야 할 때 유용합니다. 비동기 함수를 사용하여 다음과 같이 작성할 수 있습니다:

import asyncio

async def fetch_data(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.json()

@app.get("/data/")
async def get_data():
    url = "http://api.example.com/data"
    data = await fetch_data(url)
    return data

11. FastAPI의 업데이트 및 삭제

FastAPI에서는 PUT 메서드를 사용하여 리소스를 업데이트하고, DELETE 메서드를 사용하여 리소스를 삭제할 수 있습니다. 다음은 업데이트와 삭제를 수행하는 간단한 예제입니다.

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    # 업데이트 로직
    return {"item_id": item_id, **item.dict()}

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    # 삭제 로직
    return {"message": "Item has been deleted", "item_id": item_id}

12. FastAPI의 미들웨어

FastAPI는 미들웨어를 통해 요청과 응답을 가로채어 핸들링할 수 있는 기능을 제공합니다. 예를 들어, 모든 요청에 대해 로그를 기록하는 미들웨어를 작성할 수 있습니다:

from starlette.middleware.base import BaseHTTPMiddleware

class LogMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        response = await call_next(request)
        print(f"Request: {request.url}, Response Status: {response.status_code}")
        return response

app.add_middleware(LogMiddleware)

13. FastAPI와 보안

FastAPI는 OAuth2와 같은 인증 방법을 지원합니다. 이를 통해 안전하게 API를 보호하고 접근 제어를 할 수 있습니다. 아래는 간단한 보안 개요입니다:

from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # 검증 로직
    return {"access_token": form_data.username, "token_type": "bearer"}

14. 마치며

이 글에서는 FastAPI를 사용하여 백엔드 서버를 개발하고 Uvicorn을 통해 이를 실행하는 방법에 대해 살펴보았습니다. 비동기 처리, 데이터베이스 연동, RESTful API 설계 등 다양한 기능을 활용하여 강력한 웹 서버를 구축할 수 있음을 확인했습니다. FastAPI는 그 자체로도 훌륭하지만, 다양한 라이브러리와 함께 사용하여 진정한 강력함을 발휘합니다. 각자의 필요에 따라 FastAPI의 기능을 확장하여 자신만의 API 서버를 만들어 보세요!

부록: 관련 라이브러리 및 자료

FastAPI와 함께 잘 사용되는 여러 라이브러리와 자료를 소개합니다:

© 2023 FastAPI 블로그