FastAPI 서버개발, FastAPI 애플리케이션 구조화, 라우트 구현

FastAPI는 현대적인 웹 API 개발을 위한 프레임워크로, Python 언어를 기반으로 하여 비동기 프로그래밍을 지원합니다. FastAPI의 주요 장점 중 하나는 높은 성능을 유지하면서도 개발자가 직관적으로 이해하고 사용할 수 있도록 돕는 강력한 타입 시스템과 자동화된 문서 생성 기능입니다. 이 글에서는 FastAPI 서버를 개발하고 애플리케이션 구조화 방법, 그리고 라우트 구현에 대해 자세히 설명하고 예제 코드를 제공합니다.

1. FastAPI란?

FastAPI는 웹 애플리케이션의 백엔드 API를 쉽게 구축할 수 있도록 해주는 Python 프레임워크입니다. 다음과 같은 특징이 있습니다:

  • 빠른 성능: Starlette를 기반으로 하며, 비동기적이고 빠른 실행 속도를 가지고 있습니다.
  • 자동 문서 생성: Swagger UI 및 ReDoc을 통한 자동 API 문서화를 지원합니다.
  • 타입 힌팅: Python 3.6 이상의 타입 힌팅을 사용하여 코드 가독성과 유지 보수성을 높입니다.

2. FastAPI로 서버 개발 시작하기

FastAPI 설치는 간단합니다. pip를 사용하여 FastAPI와 uvicorn을 설치할 수 있습니다:

pip install fastapi uvicorn

3. 기본 FastAPI 애플리케이션 구조

FastAPI 애플리케이션은 다음과 같은 구조로 구성될 수 있습니다:

  • main.py: FastAPI 애플리케이션의 진입점입니다.
  • routers: 다양한 API 라우트를 정의하는 모듈입니다.
  • models: 데이터베이스 모델 및 Pydantic 모델을 정의하는 모듈입니다.
  • schemas: 요청 및 응답 모델을 정의하는 Pydantic 스키마입니다.
  • services: 비즈니스 로직을 처리하는 모듈입니다.

3.1 기본 FastAPI 애플리케이션 코드

아래 코드는 FastAPI의 기본 애플리케이션 구조를 보여줍니다:

from fastapi import FastAPI

app = FastAPI()

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

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

4. FastAPI 애플리케이션 라우팅

FastAPI에서 라우팅은 웹 경로와 HTTP 메서드(GET, POST, PUT, DELETE 등)에 따라 클라이언트의 요청을 처리하는 방식을 정의합니다. FastAPI는 각 라우트에 대한 HTTP 메서드를 데커레이터 형태로 작성할 수 있게 해줍니다.

4.1 라우트 구현하기

라우트를 구현하기 위해 FastAPI에 내장된 여러 데커레이터를 사용할 수 있습니다. 예를 들어, 클라이언트가 “/items/{item_id}” 경로로 GET 요청을 보낼 때 특정 아이템을 반환하는 라우트를 아래와 같이 정의할 수 있습니다:

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

4.2 다양한 HTTP 메서드 사용하기

FastAPI는 GET, POST, PUT, DELETE와 같은 다양한 HTTP 메서드를 지원합니다. 아래 예제는 POST 요청을 처리하여 클라이언트로부터 입력 받은 데이터를 반환하는 라우트를 보여줍니다:

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

5. FastAPI 라우터로 애플리케이션 구조화하기

대규모 애플리케이션에서는 모든 라우트를 main.py 파일에 정의하는 것보다 모듈화하여 관리하는 것이 효율적입니다. FastAPI에서는 `APIRouter`를 사용하여 라우트 그룹을 만들 수 있습니다.

5.1 라우터 설정하기

프로젝트 구조를 다음과 같이 설정합니다:

  • app/
    • main.py
    • routers/
      • items.py
    • models/
      • item.py

5.2 items.py 라우터 구현

items.py 파일에서 아이템 관련 모든 라우트를 정의합니다:

from fastapi import APIRouter
from models.item import Item

router = APIRouter()

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

@router.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

5.3 main.py 파일에서 라우터 포함시키기

라우터를 main.py에 포함시켜 사용합니다:

from fastapi import FastAPI
from routers.items import router as items_router

app = FastAPI()

app.include_router(items_router, prefix="/items", tags=["items"])

6. FastAPI와 데이터베이스 연동하기

FastAPI 애플리케이션에서 데이터베이스와 연동하는 것은 자주 필요하는 기능입니다. 아래 코드는 SQLAlchemy와 FastAPI를 통합하여 데이터베이스와 상호작용하는 방법을 보여줍니다.

6.1 SQLAlchemy 설치하기

SQLAlchemy와 데이터베이스 드라이버를 설치합니다:

pip install sqlalchemy databases

6.2 데이터베이스 연결 설정

database.py 파일을 생성하고 데이터베이스 연결을 설정합니다:

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
metadata = MetaData()
Base = declarative_base()

6.3 모델 정의하기

models/item.py에서 데이터베이스 모델을 정의합니다:

from sqlalchemy import Column, Integer, String
from database import Base

class Item(Base):
    __tablename__ = "items"

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

6.4 CRUD 작동 구현하기

서비스 계층에 CRUD 작동을 구현합니다:

from sqlalchemy.orm import Session
from models.item import Item

def get_item(db: Session, item_id: int):
    return db.query(Item).filter(Item.id == item_id).first()

def create_item(db: Session, item: Item):
    db.add(item)
    db.commit()
    db.refresh(item)
    return item

7. FastAPI 애플리케이션 실행하기

FastAPI 애플리케이션을 실행하기 위해 다음 명령어를 사용합니다:

uvicorn main:app --reload

8. 결론

FastAPI는 훌륭한 성능과 직관적인 코드 작성을 제공하는 웹 API 프레임워크입니다. 본 강좌에서는 FastAPI를 사용하여 서버를 개발하고 애플리케이션 구조화 방법, 라우트 구현에 대해 다루었습니다. FastAPI가 제공하는 다양한 기능들을 활용하여 보다 나은 웹 애플리케이션을 구축할 수 있기를 바랍니다.

9. 추가 자료

FastAPI 공식 문서에서 더 많은 정보와 자료를 확인할 수 있습니다: FastAPI Documentation

FastAPI 서버개발, 중복 코드 줄이기를 위한 의존성 재사용

웹 애플리케이션을 개발할 때, 코드의 중복을 줄이는 것은 소프트웨어의 유지보수성과 확장성을 높이는 중요한 작업입니다. FastAPI는 이러한 작업을 효율적으로 처리하기 위한 다양한 방법을 제공하며, 특히 의존성 주입(Dependency Injection)의 개념을 통해 중복 코드를 줄일 수 있는 뛰어난 기능을 갖추고 있습니다.

1. FastAPI 소개

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 빠른 성능과 개발 생산성을 자랑합니다. ASGI(Asynchronous Server Gateway Interface)를 기반으로 하며, 비동기 프로그래밍을 지원합니다. 데이터 검증, 직렬화, OpenAPI 및 JSON Schema에 대한 자동화된 문서화를 쉽게 처리할 수 있습니다.

2. 의존성 주입(Dependency Injection)란?

의존성 주입이란 객체나 함수가 필요로 하는 외부의 의존 객체를 주입받아 사용하는 디자인 패턴입니다. 이를 통해 객체 간의 결합도가 낮아져 코드의 재사용성이 증가하고, 테스트가 쉬워지는 장점이 있습니다.

2.1 FastAPI에서 의존성 주입 사용하기

FastAPI에서는 의존성을 정의하고 주입하는 것이 매우 간단합니다. 의존성을 정의하기 위해서는 Depends 클래스를 사용합니다. 아래 코드 예제를 통해 이를 살펴보겠습니다.

from fastapi import FastAPI, Depends, HTTPException

app = FastAPI()

def get_query_param(q: str = None):
    return q

@app.get("/items/")
async def read_item(q: str = Depends(get_query_param)):
    if q:
        return {"query": q}
    return {"query": "No query provided"}

위 예제에서는 get_query_param이라는 함수를 정의하고 여기서 query parameter를 받아옵니다. Depends를 사용하여 이를 read_item 함수에 주입하고 있습니다.

3. 중복 코드 줄이기의 필요성

웹 애플리케이션의 크기가 커질수록, 비슷한 기능을 갖는 코드 블록이 여러 곳에서 반복되는 경우가 많습니다. 이러한 중복 코드는 코드의 복잡성을 증가시키고, 유지보수의 어려움을 초래합니다. 의존성 주입을 통해 이러한 중복 코드를 줄임으로써 효율적인 코드 작성을 할 수 있습니다.

4. 의존성 재사용을 통한 코드 최적화

의존성 재사용은 FastAPI의 핵심 특징 중 하나입니다. 기본적인 의존성을 여러 라우터에 재사용할 수 있고, 이를 통해 코드의 일관성을 유지하며 중복을 제거할 수 있습니다.

4.1 공통 의존성 정의하기

예를 들어, 사용자의 인증을 처리하는 공통 의존성을 정의할 수 있습니다. 아래 코드는 JWT 인증을 위한 예시입니다.

from fastapi import Security, Depends
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # 여기에 JWT 검증 로직을 추가합니다.
    if token != "valid-token":
        raise HTTPException(status_code=401, detail="Invalid authentication credentials")
    return {"username": "user1"}

@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
    return current_user

여기서 get_current_user 함수는 JWT 토큰을 검증하는 역할을 하며, 여러 라우터에서 재사용될 수 있습니다.

4.2 동적으로 의존성 주입하기

FastAPI에서는 동적으로 의존성을 주입할 수도 있습니다. 이를 통해 상황에 따라 다른 의존성을 사용할 수 있습니다. 예를 들어, 환경에 따라 다른 데이터베이스 연결을 사용할 수 있습니다.

from fastapi import Depends

def get_database_connection():
    if app.state.environment == "production":
        return "Production DB Connection"
    return "Development DB Connection"

@app.get("/db/")
async def read_db(connection: str = Depends(get_database_connection)):
    return {"connection": connection}

위 코드에서 환경 변수를 통해 서로 다른 데이터베이스 연결을 주입받을 수 있습니다.

5. 의존성 재사용의 이점

  • 유지보수성: 중복이 제거됨으로써 코드 전반에 걸쳐 더 쉽게 수정할 수 있습니다.
  • 테스트 용이성: 더 적은 코드로 더 많은 기능을 구현할 수 있어, 테스트와 디버깅을 쉽게 할 수 있습니다.
  • 일관성: 의존성이 각기 다른 라우터에서 재사용됨으로써 코드의 일관성을 유지할 수 있습니다.

6. 고급 의존성 주입

FastAPI에서는 의존성 주입의 고급 기능도 제공하여, 클래스와 함께 사용할 수 있습니다. 이를 통해 더 복잡한 비즈니스 로직을 캡슐화할 수 있습니다. 아래는 클래스 기반의 의존성 주입 예제입니다.

class UserService:
    def get_user(self, user_id: int):
        # 데이터베이스에서 사용자 정보를 가져오는 로직
        return {"user_id": user_id, "name": "John Doe"}

def get_user_service() -> UserService:
    return UserService()

@app.get("/users/{user_id}")
async def read_user(user_id: int, user_service: UserService = Depends(get_user_service)):
    return user_service.get_user(user_id)

이 예제에서 UserService 클래스는 사용자의 정보를 제공하는 로직을 담당하며, 이를 의존성으로 주입받아 사용할 수 있습니다.

7. 결론

FastAPI는 의존성 주입을 통해 중복 코드를 최소화하고 코드의 재사용성을 극대화할 수 있는 훌륭한 도구입니다. 의존성을 통해 작성된 코드는 더 간결하고, 유지보수하기 쉬우며, 테스트가 용이합니다. 여러 가지 예제를 통해 의존성 재사용의 중요성과 이를 FastAPI에서 구현하는 방법을 살펴보았습니다.

참고 자료

FastAPI 서버개발, 스키마 – 응답, 라우터에 정의한 응답에 대한 설명

FastAPI는 현대 웹 API를 간편하게 개발할 수 있는 고속 웹 프레임워크로, Python으로 작성되었습니다. 요즘 많은 개발자들이 Flask나 Django 대신 FastAPI를 선택하는 이유는 빠르게 개발할 수 있는 장점과 다양한 기능을 제공하기 때문입니다. 본 강좌에서는 FastAPI를 이용한 서버 개발 과정에서 응답 스키마, 그리고 라우터에 정의한 응답에 대해 깊이 있게 알아보겠습니다.

1. FastAPI 소개

FastAPI는 다음과 같은 장점을 가지고 있습니다:

  • 신속하게 API 개발이 가능하다.
  • 데이터 검증을 자동으로 수행하며 인텔리센스 지원이 뛰어나다.
  • 비동기 프로그래밍을 지원하여 높은 성능을 발휘한다.
  • OpenAPI 및 JSON Schema를 자동으로 생성한다.

2. FastAPI의 응답 스키마

FastAPI는 Pydantic을 사용하여 데이터 검증 및 데이터 직렬화를 수행합니다. 이를 통해 API의 입력 및 출력 데이터의 구조를 간편하게 정의할 수 있습니다. 응답 스키마를 정의하기 위해서는 Pydantic 모델을 생성하고, 이를 FastAPI의 경로 함수의 응답 타입으로 설정하면 됩니다.

2.1 Pydantic 모델 정의

Pydantic 모델을 정의하기 위해서는 클래스를 만들어야 합니다. 아래의 예시는 사용자의 정보를 표현하기 위한 Pydantic 모델입니다:


from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str
    email: str
    full_name: str = None  # 선택적인 필드

위의 예에서 User 클래스는 FastAPI에서 사용할 응답 스키마를 정의합니다. 각 필드는 해당 데이터 타입을 지정하며, 선택적 필드는 기본값을 None으로 설정합니다.

2.2 경로 함수에서 응답 스키마 사용하기

정의된 Pydantic 모델을 FastAPI의 경로 함수의 반환 타입으로 사용하여, API의 응답 데이터 타입을 명확하게 나타낼 수 있습니다. 예를 들어:


from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}", response_model=User)
async def read_user(user_id: int):
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 코드에서 response_model=User 인자를 통해 FastAPI는 이 경로에서 반환되는 데이터가 User 모델에 맞는지 검증합니다. 만약 반환되는 데이터가 모델과 일치하지 않는 경우, FastAPI는 자동으로 오류 응답을 생성합니다.

3. 라우터에 정의한 응답

FastAPI에서는 경로를 정의하기 위해 라우터를 사용할 수 있습니다. 이는 코드의 구조를 개선하고, 여러 경로를 그룹화하여 관리하기 쉽게 합니다. 별도의 라우터를 생성하고 이를 메인 애플리케이션에 포함시켜 사용할 수 있습니다.

3.1 라우터 생성

아래는 사용자를 관리하는 라우터를 만드는 예시입니다:


from fastapi import APIRouter

user_router = APIRouter()

@user_router.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 코드는 사용자의 정보를 가져오는 API를 정의하고 있습니다. APIRouter 클래스를 인스턴스화하여 user_router 객체를 생성한 후, 경로 함수와 응답 모델을 설정합니다.

3.2 메인 애플리케이션에 라우터 포함하기

생성한 라우터를 메인 FastAPI 애플리케이션에 연결하기 위해서는 include_router 메서드를 사용합니다:


app.include_router(user_router)

이제 메인 애플리케이션은 user_router에서 정의한 모든 경로를 사용할 수 있습니다.

4. 응답의 직렬화 및 검증

FastAPI는 Pydantic을 사용하여 응답 데이터를 자동으로 직렬화합니다. 기본적으로 객체는 JSON 형식으로 변환되어 클라이언트에게 전송됩니다. 이 과정에서 FastAPI는 데이터의 유효성을 검증하기 때문에, 클라이언트는 항상 일관된 데이터를 수신할 수 있습니다.

4.1 응답 예제

이제 실제로 API를 호출해보겠습니다. 사용자가 고유한 ID를 요청하면, 서버는 해당 사용자 정보를 JSON 형식으로 반환하게 됩니다. 예를 들어:


curl -X GET "http://localhost:8000/users/1"

위 요청에 대한 응답은 다음과 같을 것입니다:


{
    "id": 1,
    "username": "JohnDoe",
    "email": "john@example.com",
    "full_name": "John Doe"
}

4.2 에러 처리

FastAPI는 모델 검증 과정에서 문제가 발생하면 자동으로 오류 응답을 생성합니다. 예를 들어, 잘못된 데이터형을 요청하면:


curl -X GET "http://localhost:8000/users/not_a_number"

서버는 다음과 같은 오류 응답을 리턴합니다:


{
    "detail": [
        {
            "loc": ["path", "user_id"],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

5. 보안과 오류 관리

API 응답을 안전하게 유지하고 오류를 효과적으로 관리하는 것은 서버 개발의 핵심 요소입니다. FastAPI는 다양한 보안 기능을 제공하며, 모든 오류를 세밀하게 제어할 수 있는 방법을 갖추고 있습니다.

5.1 OAuth2 및 JWT 인증

FastAPI는 OAuth2 및 JWT를 사용한 인증을 지원합니다. 이를 통해 API 접근을 제한하고, 사용자 데이터를 보호할 수 있습니다.

5.2 사용자 정의 오류 응답

FastAPI는 사용자 정의 오류 처리를 쉽게 할 수 있도록 지원합니다. 아래와 같이 오류 발생 시 사용자 정의 응답을 리턴하도록 설정할 수 있습니다:


from fastapi import HTTPException

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    if user_id <= 0:
        raise HTTPException(status_code=400, detail="Invalid user ID")
    return User(id=user_id, username="JohnDoe", email="john@example.com", full_name="John Doe")

위 예시는 사용자 ID가 유효하지 않을 경우 사용자 정의 오류를 발생시키는 예시입니다.

6. 마무리

FastAPI는 웹 API를 개발하는 데 많은 장점을 제공하며, 스키마 정의와 라우터를 이용한 구조적 접근 방식은 안정적이고 유지 보수가 용이한 코드를 만들 수 있게 합니다. 응답 스키마를 정의하고, 라우터를 포함하여 API 응답을 관리하는 방법에 대해 논의했습니다. 이러한 방법들을 통하여, 여러분은 더 나은 API를 설계할 수 있는 기초를 다졌을 것입니다.

FastAPI는 Python의 강력한 기능을 결합하여 웹 개발을 훨씬 용이하게 만들어 줍니다. 앞으로도 FastAPI와 함께 다양한 API를 개발해 보시길 바랍니다!

FastAPI 서버개발, 컨테이너 이미지 업로드 GCR 이용하기

FastAPI는 현대적인 웹 API를 개발하는 데 매우 유용한 프레임워크입니다. Python의 타입 힌트를 활용하여 빠르고 효율적으로 RESTful API를 구축할 수 있습니다. 이번 포스트에서는 FastAPI를 사용하여 컨테이너 이미지를 Google Cloud Registry(GCR)에 업로드하는 방법에 대해 자세히 설명하겠습니다.

1. FastAPI란?

FastAPI는 Python으로 작성된 웹 프레임워크로, 비동기 요청을 지원하며, 높은 성능과 직관적인 API를 제공합니다. 다음은 FastAPI의 주요 특징입니다:

  • 빠른 성능: Starlette와 Pydantic을 기반으로 하여 높은 성능을 보장합니다.
  • 타입 힌트 지원: Python의 타입 힌트를 활용하여 자동으로 API 문서를 생성할 수 있습니다.
  • 비동기 지원: 비동기 처리를 통해 성능을 극대화할 수 있습니다.

2. GCR(Google Container Registry)란?

GCR은 Google Cloud Platform(GCP)의 컨테이너 레지스트리로, Docker 컨테이너 이미지를 저장하고 관리하는 데 사용됩니다. GCR을 사용하면 Kubernetes 클러스터에서 쉽게 이미지를 배포할 수 있습니다. GCP의 여러 리소스와 통합되어 있어 효율적입니다.

3. FastAPI 프로젝트 설정

FastAPI 프로젝트를 설정하기 위해 다음과 같은 단계를 따릅니다:

3.1. 환경 세팅

bash
mkdir fastapi-gcr
cd fastapi-gcr
python3 -m venv venv
source venv/bin/activate
pip install fastapi uvicorn google-cloud-storage

여기서는 가상 환경을 만들고 FastAPI 및 관련 라이브러리를 설치합니다.

3.2. FastAPI 애플리케이션 구현

다음으로 FastAPI 애플리케이션을 구현합니다. 간단한 이미지 업로드 API를 생성할 것입니다.

python
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from google.cloud import storage
import os

app = FastAPI()

# GCS 클라이언트 초기화
storage_client = storage.Client()
bucket_name = 'YOUR_BUCKET_NAME'
bucket = storage_client.bucket(bucket_name)

@app.post("/upload/")
async def upload_image(file: UploadFile = File(...)):
    # 파일을 Google Cloud Storage에 업로드
    blob = bucket.blob(file.filename)
    blob.upload_from_file(file.file, content_type=file.content_type)
    
    return JSONResponse(content={"message": "File uploaded successfully!", "filename": file.filename})

위의 코드는 FastAPI의 이미지 업로드 API를 생성합니다. 파일을 GCS에 업로드하기 위해 google-cloud-storage 라이브러리를 사용합니다.

4. Google Cloud Storage 인증

GCP에 접근하기 위해서는 인증이 필요합니다. 서비스 계정 키 파일을 생성하고, 환경 변수를 설정합니다.

4.1. 서비스 계정 생성

1. GCP 콘솔에 로그인합니다.

2. IAM 및 관리 > 서비스 계정으로 이동합니다.

3. 새 서비스 계정을 만듭니다. 역할에 Storage Admin을 선택합니다.

4. JSON 키 파일을 생성하고, 이를 프로젝트 루트에 저장합니다.

4.2. 환경 변수 설정

bash
export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service-account-file.json"

5. FastAPI 애플리케이션 실행

FastAPI 웹 서버를 실행하려면 다음 명령어를 사용합니다:

bash
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

6. GCR에 Docker 이미지 배포하기

Docker 이미지를 GCR에 배포하기 위한 설정을 진행합니다.

6.1. Dockerfile 생성

애플리케이션을 도커 이미지로 패키징하기 위해 Dockerfile을 만듭니다.

Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8

COPY ./app /app
WORKDIR /app
RUN pip install google-cloud-storage

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

6.2. Docker 이미지 빌드

bash
docker build -t gcr.io/YOUR_PROJECT_ID/fastapi-gcr .

6.3. GCR에 로그인

bash
gcloud auth configure-docker

6.4. Docker 이미지 푸시

bash
docker push gcr.io/YOUR_PROJECT_ID/fastapi-gcr

7. 결론

이번 포스트에서는 FastAPI를 사용하여 GCR에 이미지를 업로드하는 간단한 API를 구현하는 과정을 살펴보았습니다. FastAPI는 쉽고 직관적인 API 개발을 지원하며, GCR은 Docker 이미지를 효율적으로 관리할 수 있게 해줍니다.

FastAPI와 GCR을 활용한 웹 서비스 구축은 클라우드 환경에서의 유연한 확장이 가능하게 하여, 실제 서비스에서 큰 장점을 제공합니다. 다양한 기능과 성능을 바랑하는 FastAPI를 통해 여러분의 웹 애플리케이션을 더욱 발전시키길 바랍니다.

FastAPI 서버개발, 경로 매개변수 및 쿼리 매개변수 사용하기

FastAPI는 현대적인 웹 애플리케이션 개발을 위한 강력하고 효율적인 웹 프레임워크입니다. 특히 RESTful API를 쉽게 구축할 수 있도록 설계되어 있으며, Python의 타입 힌트를 활용하여 높은 성능을 자랑합니다. 본 포스트에서는 FastAPI에서 경로 매개변수쿼리 매개변수를 사용하는 방법에 대해 상세히 설명하겠습니다.

1. FastAPI 소개

FastAPI는 Starlette와 Pydantic을 기반으로 만들어진 현대적인 웹 프레임워크로, 다음과 같은 특징을 가지고 있습니다:

  • 비동기 프로그래밍 지원
  • 자동화된 문서화 지원 (Swagger UI, ReDoc)
  • 입력 데이터의 유효성 검사 및 직렬화
  • 높은 성능

2. 환경 설정

FastAPI를 사용하기 위해서는 Python과 pip가 설치되어 있어야 합니다. FastAPI와 Uvicorn을 설치하려면 다음 명령어를 실행합니다:

pip install fastapi uvicorn

3. FastAPI 서버 기본 구조

다음은 FastAPI 서버의 기본 구조를 정의한 예제입니다. 아래와 같이 구조를 잡아 초기 설정을 진행합니다:

from fastapi import FastAPI

app = FastAPI()

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

위 코드를 main.py라는 파일에 저장합니다. 서버를 실행하기 위해 아래 명령어를 실행하십시오:

uvicorn main:app --reload

이제 브라우저에서 http://127.0.0.1:8000에 접속하면 “Welcome to FastAPI!”라는 메시지를 확인할 수 있습니다.

4. 경로 매개변수 사용하기

경로 매개변수는 URL 경로의 일부로 사용되는 매개변수입니다. 예를 들어, 특정 유저의 정보를 조회하는 API를 만들 때 사용할 수 있습니다.

4.1 기본적인 경로 매개변수 예제

경로 매개변수를 사용하는 예제를 살펴보겠습니다. 아래 코드는 유저 ID를 받아 해당 유저의 정보를 반환하는 API를 구현한 것입니다:

from fastapi import FastAPI

app = FastAPI()

# 간단한 유저 데이터베이스 (예: 딕셔너리)
users = {1: {"name": "Alice"}, 2: {"name": "Bob"}}

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    user = users.get(user_id)
    if user:
        return user
    return {"message": "User not found"}

위 예제에서 user_id는 경로 매개변수입니다. 사용자가 /users/1를 요청하면, 서버는 유저 ID가 1인 유저의 정보를 반환합니다. 만약 존재하지 않는 ID를 요청할 경우, “User not found” 메시지를 반환합니다.

4.2 경로 매개변수의 유효성 검사

FastAPI는 경로 매개변수의 타입을 자동으로 검사합니다. 예를 들어, user_id: int로 정의했기 때문에, 만약 사용자가 /users/abc와 같이 요청하면 422 Unprocessable Entity 에러가 발생합니다. 적절한 데이터 타입을 전송할 것이라는 기대를 통해 API의 안정성을 증가시킵니다.

4.3 경로 매개변수와 다양한 타입

경로 매개변수는 다양한 타입을 사용할 수 있습니다. 아래 예제에서는 문자열과 부동 소수점 숫자를 사용하는 방법을 보여드립니다:

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

여기서 item_id는 문자열이며, q는 쿼리 매개변수로 부동 소수점 타입입니다. /items/abc?q=3.14와 같은 요청은 정상적으로 처리됩니다.

5. 쿼리 매개변수 사용하기

쿼리 매개변수는 URL의 쿼리 문자열에서 전달되는 매개변수입니다. GET 요청에서 주로 사용되며, 주어진 데이터에 대해 필터링하거나 추가 정보를 요청하는 데 사용됩니다.

5.1 기본적인 쿼리 매개변수 예제

다음은 쿼리 매개변수를 사용하여 사용자 목록을 필터링하는 예제입니다:

from fastapi import FastAPI
from typing import Optional

app = FastAPI()

users = {
    1: {"name": "Alice", "age": 28},
    2: {"name": "Bob", "age": 34},
    3: {"name": "Charlie", "age": 22},
}

@app.get("/users/")
async def filter_users(min_age: Optional[int] = None):
    filtered_users = {uid: user for uid, user in users.items() if (min_age is None or user["age"] >= min_age)}
    return filtered_users

위의 예제에서 min_age는 선택적인 쿼리 매개변수로 어떤 유저 목록을 반환할지를 결정합니다. 사용자가 /users/?min_age=30를 호출하면 나이가 30세 이상의 사용자만 반환됩니다.

5.2 쿼리 매개변수의 기본값

쿼리 매개변수는 기본값을 지정할 수 있습니다. 예를 들어, 기본값을 0으로 설정하면 클라이언트가 매개변수를 제공하지 않는 경우에도 호출이 가능해집니다:

@app.get("/users/")
async def filter_users(min_age: int = 0):
    filtered_users = {uid: user for uid, user in users.items() if user["age"] >= min_age}
    return filtered_users

이 경우, 기본적으로 모든 사용자가 반환됩니다. 사용자가 /users/?min_age=30와 같이 요청하면, 나이가 30세 이상의 사용자만 필터링되어 반환됩니다.

5.3 복수의 쿼리 매개변수 사용하기

쿼리 매개변수를 여러 개 지정할 수도 있습니다. 예를 들어, 사용자 나이와 이름으로 필터링하는 API는 아래와 같이 구현할 수 있습니다:

@app.get("/users/")
async def filter_users(min_age: Optional[int] = None, name: Optional[str] = None):
    filtered_users = {uid: user for uid, user in users.items() 
                      if (min_age is None or user["age"] >= min_age) and 
                      (name is None or user["name"] == name)}
    return filtered_users

위 예제는 나이와 이름으로 필터링하는 구조입니다. 예를 들어, /users/?min_age=28&name=Alice를 호출하면 나이가 28세 이상이면서 이름이 ‘Alice’인 사용자만 반환됩니다.

6. FastAPI의 데이터 모델 사용하기

데이터베이스와 상호작용하는 API를 개발할 때 Pydantic 모델을 활용하면, 입력 데이터의 유효성을 더욱 쉽게 검사할 수 있습니다. 모델을 정의하고 이를 경로 매개변수 또는 쿼리 매개변수로 사용할 수 있습니다.

6.1 Pydantic 모델 정의하기

다음은 FastAPI에서 Pydantic 모델을 사용하여 유저의 정보를 구조화하는 예제입니다:

from pydantic import BaseModel

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

@app.post("/users/")
async def create_user(user: User):
    user_id = len(users) + 1
    users[user_id] = user.dict()
    return {"user_id": user_id, "user": user}

위 코드는 유저 정보를 JSON으로 전송받아 새로운 유저를 생성하는 API를 구현한 것입니다. JSON 형식의 데이터를 입력하면 유저 ID와 함께 생성된 사용자 정보를 반환합니다.

7. 결론

FastAPI는 경로 매개변수와 쿼리 매개변수를 유연하고 강력하게 처리할 수 있는 기능을 제공합니다. 이러한 매개변수들을 통해 다양한 형태의 API를 쉽게 설계할 수 있습니다. 본 블로그 포스트에서는 기본적인 사용 방법을 소개하였으나, 실무에서는 보다 복잡한 비즈니스 로직을 구현하고, 다양한 데이터 처리 기법을 활용하여 제품의 가치를 높일 수 있습니다.

FastAPI를 활용한 서버 개발을 통해 성능 높은 API를 손쉽게 구축해보세요. 이제 여러분도 FastAPI의 매력을 느끼고 실제 애플리케이션에 적용하여 더욱 발전된 서비스를 만들어 나가길 바랍니다!