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 서버개발, SQLAlchemy의 DB 모델 정의

FastAPI는 Python으로 웹 애플리케이션을 개발하기 위해 설계된 모던 웹 프레임워크로, 매우 빠르며 비동기 프로그래밍을 지원합니다. 이번 포스트에서는 FastAPI의 백엔드 개발 환경에서 SQLAlchemy를 사용하여 데이터베이스 모델을 정의하는 방법에 대해 자세히 설명하겠습니다. SQLAlchemy는 Python의 ORM(Object Relational Mapping) 라이브러리로, 데이터베이스와의 상호작용을 더 간편하게 만들어줍니다.

1. FastAPI와 SQLAlchemy 소개

FastAPI는 다음과 같은 몇 가지 주요 이점을 가지고 있습니다:

  • 비동기 지원: Python의 asyncawait 구문을 사용하여 비동기 프로그래밍을 간편하게 구현할 수 있습니다.
  • 자동화된 문서화: FastAPI는 OpenAPI 스펙을 기반으로 클라이언트를 위한 API 문서를 자동으로 생성합니다.
  • 고성능: Starlette 위에 구축되어 있어 높은 성능을 자랑합니다.

SQLAlchemy는 관계형 데이터베이스와 상호작용하기 위한 ORM으로 다음과 같은 이점이 있습니다:

  • 데이터베이스 독립성: 여러 종류의 데이터베이스와 호환됩니다.
  • 복잡한 쿼리를 쉽게 작성: SQLAlchemy의 쿼리 빌더를 사용하면 복잡한 SQL 쿼리를 쉽게 작성할 수 있습니다.
  • 모델 정의: Python 클래스 정의를 통해 데이터베이스 모델을 직관적으로 생성할 수 있습니다.

2. 개발 환경 설정

FastAPI와 SQLAlchemy를 사용하기 위해서는 우선 Python이 설치되어 있어야 합니다. 각 패키지를 설치하는 과정은 다음과 같습니다.

pip install fastapi[all] sqlalchemy

참고: 위의 명령어에서 fastapi[all]는 FastAPI와 함께 uvicorn과 같은 모든 의존성을 설치합니다.

3. SQLAlchemy DB 모델 정의하기

SQLAlchemy를 사용하여 데이터베이스 모델을 정의하려면 몇 가지 단계를 거쳐야 합니다:

  1. SQLAlchemy 엔진 생성
  2. 세션 클래스 정의
  3. 데이터베이스 모델 정의
  4. 테이블 생성

3.1 SQLAlchemy 엔진 생성

데이터베이스 연결을 위해 SQLAlchemy 엔진을 생성해야 합니다. 이는 데이터베이스 URL을 통해 이루어집니다. 예를 들어, SQLite 데이터베이스를 사용할 경우 아래와 같이 설정할 수 있습니다.

from sqlalchemy import create_engine

DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})

3.2 세션 클래스 정의

SQLAlchemy의 세션은 데이터베이스에 대한 트랜잭션을 관리합니다. 아래 코드를 통해 세션 클래스를 정의할 수 있습니다.

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

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

3.3 데이터베이스 모델 정의

이제 SQLAlchemy의 Base 클래스를 상속받아 원하는 데이터베이스 모델을 정의할 수 있습니다. 예를 들어, 사용자 정보를 저장하기 위한 User 모델은 다음과 같이 정의할 수 있습니다.

from sqlalchemy import Column, Integer, String, Boolean

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)
    is_active = Column(Boolean, default=True)

3.4 테이블 생성하기

모델 정의가 끝났다면 실제 데이터베이스에 테이블을 생성해야 합니다. 다음과 같은 코드를 사용하여 테이블을 생성할 수 있습니다:

Base.metadata.create_all(bind=engine)

4. FastAPI와 SQLAlchemy 통합하기

이제 FastAPI를 사용해 만든 API와 SQLAlchemy 데이터베이스 모델을 통합할 차례입니다. 이를 위해 FastAPI 경로에서 CRUD(Create, Read, Update, Delete) 작업을 처리하는 엔드포인트를 작성합니다.

4.1 FastAPI 애플리케이션 생성

from fastapi import FastAPI

app = FastAPI()

4.2 CRUD API 엔드포인트 작성

다음으로, CRUD 작업을 위한 엔드포인트를 정의합니다.

4.2.1 Create: 사용자 생성

from fastapi import Depends, HTTPException
from sqlalchemy.orm import Session

# 의존성 주입을 위한 함수
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

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

4.2.2 Read: 사용자 조회

@app.get("/users/{user_id}", response_model=User)
def read_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user

4.2.3 Update: 사용자 업데이트

@app.put("/users/{user_id}", response_model=User)
def update_user(user_id: int, user: User, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.id == user_id).first()
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    
    db_user.username = user.username
    db_user.email = user.email
    db.commit()
    db.refresh(db_user)
    return db_user

4.2.4 Delete: 사용자 삭제

@app.delete("/users/{user_id}")
def delete_user(user_id: int, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.id == user_id).first()
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    db.delete(db_user)
    db.commit()
    return {"detail": "User deleted"}

5. 결론

이 글에서 우리는 FastAPI와 SQLAlchemy를 사용하여 데이터베이스 모델을 정의하고, 이를 기반으로 CRUD API를 구축하는 방법에 대해 알아보았습니다. FastAPI의 비동기 지원과 SQLAlchemy의 ORM 기능을 결합하면 Python으로 웹 애플리케이션을 효율적으로 개발할 수 있습니다. 이 과정을 통해 더 나은 백엔드 시스템을 구축하고, 확장 가능한 API를 만들 수 있습니다.

추가적으로 FastAPI의 기능을 이용하여 데이터 유효성 검증, 쿼리 파라미터 처리, JWT 인증, CORS 설정 등 다양한 기능을 적용할 수 있습니다. 이러한 기능들은 실제 실무에서 매우 유용하게 사용될 수 있습니다.

FastAPI와 SQLAlchemy의 기본 사용법을 익힌 후에는 복잡한 비즈니스 로직을 추가하여 더욱 정교한 애플리케이션을 만들어 가는 과정을 통해 더 큰 발전을 이룰 수 있을 것입니다.

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의 매력을 느끼고 실제 애플리케이션에 적용하여 더욱 발전된 서비스를 만들어 나가길 바랍니다!

FastAPI 서버개발, RESTful API 설계 원칙과 FastAPI의 활용

RESTful API 설계 원칙과 FastAPI의 활용

1. FastAPI란?

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 빠르고, 사용하기 쉬우며, RESTful API 서버를 구축하기 위해 최적화되었습니다. 이 프레임워크는 Pydantic과 Starlette를 기반으로 하고 있으며, 비동기 프로그래밍을 지원하여 높은 성능을 자랑합니다. FastAPI의 주요 강점 중 하나는 데이터 유효성 검사와 스키마 생성을 자동으로 수행할 수 있다는 점입니다. 이러한 기능은 개발자 경험을 향상시키고 개발 시간을 단축시킵니다.

2. RESTful API란?

REST(Representational State Transfer)는 웹에서 자원을 정의하고 자원에 대한 상호작용을 정의하는 아키텍처 스타일입니다. RESTful API는 이러한 원칙을 따르는 웹 서비스로, 자원에 HTTP 메서드를 사용하여 접근합니다. REST 아키텍처는 다음과 같은 기본 원칙을 가지고 있습니다:

  • 자원 지향: API는 고유한 URI로 자원을 식별합니다.
  • 무상태: 클라이언트와 서버 간의 상호작용은 독립적이며, 서버는 클라이언트의 상태를 유지하지 않습니다.
  • 표현: 자원은 다양한 표현 형식(JSON, XML 등)으로 제공될 수 있습니다.
  • HTTP 메서드 활용: GET, POST, PUT, DELETE 등의 메서드를 사용하여 자원에 대한 CRUD(Create, Read, Update, Delete) 작업을 수행합니다.

3. FastAPI 설치하기

FastAPI를 사용하기 위해서는 Python과 pip가 필요합니다. 아래는 FastAPI와 함께 Uvicorn 서버를 설치하는 방법입니다:

pip install fastapi uvicorn

Uvicorn은 FastAPI 애플리케이션을 실행하는 ASGI 서버입니다.

4. FastAPI로 간단한 RESTful API 구축하기

4.1. 기본 예제

FastAPI로 간단한 RESTful API를 만들어보겠습니다. 다음은 사용자 정보를 처리하는 API입니다:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

users = []

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

@app.get("/users/")
def get_users():
    return users

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

@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    for user in users:
        if user.id == user_id:
            users.remove(user)
            return {"message": "User deleted successfully"}
    return {"error": "User not found"}

위의 코드는 FastAPI를 사용하여 사용자 정보를 추가, 조회, 삭제할 수 있는 간단한 API를 생성합니다.

5. RESTful API 설계 원칙

5.1. URI 설계

RESTful API에서는 자원의 URI를 명확하게 설계하는 것이 중요합니다. URI는 자원을 표현하고, 클라이언트가 REST API를 통해 자원에 접근할 수 있게 합니다. 다음은 좋은 URI 설계의 예입니다:

  • GET /users: 모든 사용자 목록 조회
  • POST /users: 새 사용자 추가
  • GET /users/{id}: 특정 사용자 조회
  • DELETE /users/{id}: 특정 사용자 삭제

URI를 설계할 때는 명사 형태를 사용하는 것이 좋습니다. 동사는 HTTP 메서드를 통해 전달됩니다.

5.2. HTTP 메서드 사용

RESTful API에서는 자원에 대한 행위를 표현하기 위해 HTTP 메서드를 사용합니다. 각 메서드의 용도는 다음과 같습니다:

  • GET: 서버로부터 자원 조회
  • POST: 서버에 새로운 자원 생성
  • PUT: 서버의 자원 수정
  • DELETE: 서버의 자원 삭제

5.3. 상태 코드 사용

RESTful API에서는 적절한 HTTP 상태 코드를 사용하여 클라이언트에게 요청의 결과를 전달해야 합니다. 주요 상태 코드는 다음과 같습니다:

  • 200 OK: 요청 성공
  • 201 Created: 자원 생성 성공
  • 204 No Content: 자원 삭제 성공
  • 404 Not Found: 요청한 자원 없음
  • 400 Bad Request: 잘못된 요청
  • 500 Internal Server Error: 서버 오류

6. FastAPI의 고급 기능

6.1. 데이터 검증 및 스키마

FastAPI는 Pydantic을 사용하여 데이터 검증과 스키마 관리를 제공합니다. 요청의 본문에서 전달되는 데이터에 대해 자동으로 검증을 수행하고, 잘못된 데이터가 들어오면 에러를 반환합니다. 예를 들어, 다음과 같이 데이터 검증을 추가할 수 있습니다:

from pydantic import EmailStr

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

여기서 email 필드는 이메일 형식의 문자열만 허용됩니다.

6.2. 의존성 주입

FastAPI는 의존성 주입을 지원하여 코드의 재사용성을 높이고, 테스트를 쉽게 할 수 있습니다. 의존성은 FastAPI의 @Depends를 사용하여 정의할 수 있습니다. 예를 들어:

from fastapi import Depends

def get_query_param(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

@app.get("/items/")
def get_items(queries: dict = Depends(get_query_param)):
    return {"queries": queries}

여기서 get_query_param 함수는 쿼리 파라미터를 처리하는 의존성으로 사용됩니다.

7. FastAPI와 Swagger UI

FastAPI는 Swagger UI를 자동으로 생성하여 API 문서를 쉽게 볼 수 있도록 제공합니다. 서버를 실행한 후, 브라우저에서 http://localhost:8000/docs로 이동하면 API 문서를 확인할 수 있습니다. 이 문서에서는 각 API 엔드포인트의 요청 및 응답 형식, 설명 등을 확인할 수 있습니다.

8. FastAPI 프로젝트 구조

FastAPI 프로젝트의 구조는 의견에 따라 다를 수 있지만, 일반적으로 다음과 같이 구성할 수 있습니다:

my_fastapi_app/
    ├── app/
    │   ├── __init__.py
    │   ├── main.py
    │   ├── models.py
    │   ├── routers/
    │   │   ├── __init__.py
    │   │   ├── user.py
    │   │   └── item.py
    │   └── services/
    │       ├── __init__.py
    │       └── user_service.py
    └── requirements.txt

여기에서 main.py는 FastAPI 애플리케이션을 실행하는 파일이며, models.py는 데이터 모델을 정의하고, routers/에는 각각의 API 엔드포인트를 정의하는 라우터를 구현합니다. services/ 폴더에는 비즈니스 로직을 분리하여 관리할 수 있습니다.

9. FastAPI로 안전한 API 만들기

9.1. 인증 및 인가

FastAPI는 OAuth2와 JWT(Json Web Token)를 사용하여 인증 및 인가 기능을 쉽게 구현할 수 있습니다. 예를 들어, JWT 토큰을 생성하고 검증하는 간단한 방법은 다음과 같습니다:

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.post("/token")
async def login(form: OAuth2PasswordRequestForm = Depends()):
    # 사용자 인증 로직 구현 (mock)
    if form.username == "user" and form.password == "password":
        return {"access_token": "your_token", "token_type": "bearer"}
    raise HTTPException(status_code=400, detail="Invalid credentials")

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    # 토큰 검증 로직 구현

10. FastAPI에서 테스트하기

FastAPI는 테스트를 매우 쉽게 만들어줍니다. Python의 비동기 테스트 기능을 사용하여 API를 테스트할 수 있습니다. 아래는 테스트의 간단한 예입니다:

from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_create_user():
    response = client.post("/users/", json={"id": 1, "name": "John", "age": 30})
    assert response.status_code == 200
    assert response.json() == {"id": 1, "name": "John", "age": 30}

위의 예제에서는 FastAPI의 TestClient를 사용하여 API 호출을 테스트합니다.

11. FastAPI 배포하기

FastAPI 애플리케이션을 배포하기 위해 Uvicorn을 사용하여 서버를 실행할 수 있습니다. 기본적인 실행 명령어는 다음과 같습니다:

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

여기서 --reload 옵션은 개발 모드에서 소스 코드를 수정할 때 자동으로 서버를 다시 시작합니다. 프로덕션 환경에서는 `–host`, `–port`, `–reload` 옵션을 적절히 설정해야 합니다.

12. 마치며

FastAPI는 손쉬운 RESTful API 개발을 위해 필요한 모든 기능을 제공하는 강력한 프레임워크입니다. 이 글에서 다룬 내용을 통해 FastAPI를 사용하여 RESTful API를 설계하고 구현하는 방법을 익혔기를 바랍니다. FastAPI의 다양한 기능을 활용하여 더욱 효율적이고 안전한 API를 개발해보세요.