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를 개발해보세요.