FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트에 기초한 Python의 API를 빌드하기 위한 웹 프레임워크라고 소개하고 있다.
쉽게 말해서 웹 개발 중에서 백엔드 파트를 파이썬으로 만들 수 있게 해주는 프레임워크다.
웹 개발을 하기 전에 RESTful API라는 개념을 알아야 한다.
RESTful API
RESTful API는 REST(Representational State Transfer) 스타일을 따르는 API로 웹 서비스를 설계하고 구현하는 방법론이다.
초심자가 이해하기 쉬운거 같은 대략적인 특징 몇가지만 정리해보았다.
1. 리소스 (Resource) 중심
- 모든 것을 리소스(자원) 로 표현 (주로 복수형 명사 사용)
- 각 리소스는 고유한 URI로 식별
- 예: /users, /products
2. 리소스 조작 Operation (조작 혹은 동작)은 HTTP 메소드로 표현
- GET: 데이터 조회
- POST: 데이터 생성
- PUT: 데이터 전체 수정
- PATCH: 데이터 부분 수정
- DELETE: 데이터 삭제
3. 계층 관계는 '/'로 표현
- 예: /users/123/orders
4. 필터링, 정렬, 페이징은 쿼리 파라미터로 표현
- 예: /products?category=electronics&sort=price
DB와 함께 생각하는 예시
DB와 연동해서 생각하면 다음과 같은 예시를 생각할 수 있다.
왓챠와 같은 영화 평점 사이트가 있다고 하자.
GET
어떤 영화 A를 누르면 해당 영화 A의 평점 디테일 페이지에 필요한 내용들을 가져온다.
따라서 GET을 통해서 영화 A에 대한 평균 평점과 유저들의 리뷰 목록들을 가져와야 한다.
POST
이번에는 유저 Kim이 영화 A에 평점을 준다고 하자.
그렇다면 POST를 통해서 유저 Kim이 영화 A에 점수 N을 주었다고 DB에 인스턴스를 추가해야 한다.
이때 DB에는 데이터 타입이 정해져있으므로 유저, 영화, 점수에 대한 데이터 타입도 지정해주어야 에러가 발생하지 않는다.
FastAPI 예시
GET
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
items의 하위 계층에서 특정한 item_id에 해당하는 것을 가져온다.
위에서 언급한 이유 때문에 item_id를 int로 지정한다.
POST
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
items 경로로 요청을 보내서 item 항목을 추가한다.
이때 pydantic의 형식으로 데이터 형식을 지정할 수 있다.
DB의 속성별 데이터 타입과 연동하기 편하다.
그리고 str | None = None을 통해서 description을 선택적인 항목으로 만든다.
tax 역시 마찬가지 논리로 인해서 선택적인 항목이 된다.
따라서 description와 tax는 없어도 Item 클래스에 의한 객체가 생성 가능하다.
아래는 그 예시다.
pydantic의 BaseModel의 예시
example = Item(
name="Sample Item",
description="This is a sample item.",
price=19.99,
tax=1.5
)
example.name, example.description, example.price, example.tax
>> ('Sample Item', 'This is a sample item.', 19.99, 1.5)
sample2 = Item(
name="Sample Item 2",
price=29.99,
)
sample2.name, sample2.description, sample2.price, sample2.tax
>> sample2 = Item(
name="Sample Item 2",
price=29.99,
)
sample2.name, sample2.description, sample2.price, sample2.tax
Query Parameters 쿼리 매개변수
필수가 아닌 쿼리 매개변수
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
쿼리 매개변수 q는 Optional[str] 자료형입니다. 즉, str 자료형이지만 None 역시 될 수 있음을 뜻한다.
fastapi의 Query 매개 변수를 이용해서 최대 길이를 지정하고 기본값을 None으로 설정할 수 있다.
그리고 실제로 기본값은 None이기 때문에 FastAPI는 이 매개변수가 필수가 아니라는 것을 알게 된다.
쿼리 매개변수를 필수로 설정
@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
숫자형 쿼리 매개변수 검증
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: str,
size: float = Query(gt=0, lt=10.5),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
item_id는 ge (크거나 같은(greater than or equal)) 0, le (작거나 같은(less than or equal)) 1000 이므로 [0, 1000]의 범위를 갖는다.
size의 경우 gt (크거나(greater than)) 0과 lt (작거나(less than)) 이므로 (0, 10.5)의 범위를 갖는다.
다중 매개변수
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[str, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
results = {"item_id": item_id, "item": item, "user": user}
return results
pydantic에서 BaseModel 형식의 매개변수를 여러개 동시에 사용할 수 있다.
모델 속성과 필드 Model Attributes and Field
pydantic의 Field를 통해서 데이터의 범위를 조절하여 검증하거나 메타데이터를 추가할 수 있다.
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = Field(
default=None, title="The description of the item", max_length=300
)
price: float = Field(gt=0, description="The price must be greater than zero")
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
results = {"item_id": item_id, "item": item}
return results
CORS (Cross Origin Resoures Sharing) 설정
프론트엔드 서버와 백엔드 서버는 보통 서로 주소가 다르기 마련인데 CORS를 설정해서 프론트엔드 서버에서 HTTP 요청을 가능하도록 만든다.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http://localhost",
"http://localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
References:
https://github.com/fastapi/fastapi
https://fastapi.tiangolo.com/ko/tutorial/
https://en.wikipedia.org/wiki/REST
https://velog.io/@somday/RESTful-API-%EC%9D%B4%EB%9E%80
https://learn.microsoft.com/ko-kr/rest/api/azure/
https://blog.pumpkin-raccoon.com/115
https://pkgpl.org/2023/09/05/restful-api/
https://developer.mozilla.org/ko/docs/Web/HTTP/Reference/Status
https://junglast.com/blog/fastapi-reuse-query-parameter
https://jeeqong.tistory.com/entry/fastapi-multi-query-filter-api
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS
https://hannut91.github.io/blogs/infra/cors
'개발 > Backend' 카테고리의 다른 글
LLM 기반 추천 시스템 백엔드 - LLM 추천 파트 (0) | 2025.04.25 |
---|---|
LLM 기반 추천 시스템 백엔드 (0) | 2025.04.25 |
SQLAlchemy 기초 (0) | 2025.04.23 |
백엔드 기초 개념과 가이드 라인 (1) | 2025.03.30 |