FastAPI는 현대적인 웹 프레임워크로, Python으로 작성된 비동기 웹 애플리케이션을 구축하는 데 매우 유용합니다. 특히 RESTful API와 GraphQL API를 손쉽게 구현할 수 있습니다. 이 글에서는 FastAPI로 두 가지 API를 통합하여 사용하는 방법에 대해 자세히 설명하겠습니다.
1. FastAPI란?
FastAPI는 Python 3.6 이상에서 사용할 수 있는 비동기 웹 프레임워크입니다. 자동 문서화, 데이터 유효성 검사 등에 강력한 기능을 가지고 있습니다. 또한, Starlette를 기반으로 하여 높은 성능과 비동기 작업을 지원합니다.
2. REST API와 GraphQL API의 차이
REST API는 자원에 대한 CRUD(Create, Read, Update, Delete) 작업을 수행하는데, 각 자원은 고유한 URI를 가지고 있습니다. 반면, GraphQL API는 클라이언트가 필요한 데이터를 명확하게 요청할 수 있는 쿼리 언어를 제공합니다. GraphQL을 사용하면 데이터 전송량을 줄이고, 클라이언트에서 원하는 형식으로 데이터를 요청할 수 있어 효율적입니다.
2.1 REST API의 예
GET /users : 모든 사용자 정보 가져오기
POST /users : 새로운 사용자 추가하기
GET /users/1 : 특정 사용자 정보 가져오기
PUT /users/1 : 특정 사용자 정보 수정하기
DELETE /users/1 : 특정 사용자 삭제하기
2.2 GraphQL의 예
query {
users {
id
name
}
}
mutation {
createUser(name: "Alice") {
id
name
}
}
3. FastAPI 설치
FastAPI를 사용하기 위해 필요한 패키지를 설치합니다. 먼저 Python과 pip가 설치되어 있는지 확인합니다. 다음 명령어를 사용하여 FastAPI와 Uvicorn을 설치할 수 있습니다.
pip install fastapi uvicorn
4. FastAPI 프로젝트 구조
FastAPI 프로젝트 구조는 아래와 같이 설정할 수 있습니다.
my_fastapi_project/
├── main.py
├── models.py
├── schemas.py
├── database.py
└── graphql.py
5. FastAPI로 REST API 구현하기
이제 FastAPI를 사용하여 REST API를 구현해보겠습니다. 먼저 models.py
파일에서 데이터 모델을 정의합니다.
from pydantic import BaseModel
from typing import List
class User(BaseModel):
id: int
name: str
5.1 데이터베이스 설정
데이터베이스 접속을 위해 아래와 같은 database.py
파일을 만듭니다. SQLAlchemy를 사용하여 데이터베이스와 상호작용합니다.
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class UserDB(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
Base.metadata.create_all(bind=engine)
5.2 REST API 엔드포인트 만들기
이제 main.py
파일에 REST API 엔드포인트를 작성합니다.
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from database import SessionLocal, UserDB, engine
from models import User
app = FastAPI()
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_user = UserDB(name=user.name)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
@app.get("/users/", response_model=List[User])
def read_users(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
users = db.query(UserDB).offset(skip).limit(limit).all()
return users
6. FastAPI로 GraphQL API 구현하기
이제 GraphQL API를 구현해보겠습니다. graphql.py
파일에서 GraphQL 스키마를 정의합니다.
from fastapi import FastAPI
from fastapi.openapi.docs import get_swagger_ui_html
from graphene import ObjectType, String, Schema, Field, List
from models import User, UserDB
from database import SessionLocal
class UserType(ObjectType):
id = String()
name = String()
class Query(ObjectType):
users = List(UserType)
def resolve_users(self, info):
db = SessionLocal()
return db.query(UserDB).all()
schema = Schema(query=Query)
app = FastAPI()
@app.get("/graphql/")
async def graphql_endpoint():
return await Query().execute()
7. 두 API 통합하기
이제 두 가지 API를 통합할 시간입니다. 다음과 같이 FastAPI의 라우터와 GraphQL endpoint를 함께 사용할 수 있습니다.
from fastapi import FastAPI
from fastapi_graphql import GraphQLRouter
from database import Base, engine
from graphql import schema
app = FastAPI()
Base.metadata.create_all(bind=engine)
app.include_router(GraphQLRouter(schema=schema), prefix="/graphql")
# 기존 REST API 엔드포인트 코드...
8. 서버 실행하기
마지막으로, Uvicorn을 사용하여 FastAPI 서버를 실행합니다. 아래 명령어로 서버를 실행할 수 있습니다.
uvicorn main:app --reload
9. API 테스트
서버가 실행되면 http://127.0.0.1:8000/docs
주소에서 Swagger UI를 통해 REST API를 테스트할 수 있습니다. GraphQL API는 http://127.0.0.1:8000/graphql/
에서 테스트할 수 있습니다.
10. 결론
FastAPI를 사용하면 REST API와 GraphQL API를 손쉽게 구축하고 통합할 수 있습니다. 이번 튜토리얼을 통해 두 가지 API 유형을 함께 사용하는 방법을 배웠습니다. 이를 통해 개발자는 필요에 따라 API를 선택할 수 있으며, 클라이언트의 요구를 충족할 수 있게 됩니다.
추가적인 질문이나 궁금증이 있다면 댓글로 남겨주시면 답변해드리겠습니다!