FastAPI로 개발하기
🗂️ 목차
1. intro
2차 프로젝트로 금융 서비스에 LLM을 연동하기 위해서 파이썬 웹 프레임워크가 필요했다. DRF(Django Rest Framework)와 Flask로 프로젝트를 진행해 본 경험이 있었지만,
백엔드는 SpringBoot를 메인으로 가져가기 위해서 FastAPI를 사용해보고자 한다.
이번 글에서는 가상환경을 만들고, FastAPI 앱을 띄운 뒤, Swagger UI(/docs) 로 API가 정상 노출되는지 확인해 볼 예정이다.
(LLM 연동은 다음 글에서 다룰 예정 😉)
2. FastAPI란?
FastAPI는 파이썬 기반의 웹 프레임워크로 API를 만드는데 집중적으로 사용되며, 이름에 걸맞게 빠르다고 한다.
🔍 FastAPI 장점
- 타입 안정성: typing + Pydantic으로 요청/응답 스키마 검증 자동
- 함수에 타입 힌트를 달면, 그걸 근거로 요청 검증과 응답 직렬화를 자동으로 처리
- 런타임시 Pydantic이 데이터 타입을 변환/검증해 버그를 초기에 차단해줌
- 자동 문서화 : OpenAPI 스펙 → /docs 바로 생성
- 자동으로 API 문서(웹)을 통해서 바로 테스트 할 수 있음 (Swagger)
- 고성능/비동기: ASGI(Uvicorn)로 동시성 우수
- FastAPI는 WSGI(동기) 대신 ASGI(비동기) 스택(Starlette + Uvicorn)을 사용
I/O 바운드 작업(DB, 외부 API, 파일, 스트리밍)에 동시성 처리 강함
** ASGI : 파이썬 웹 서버, 프레임워크, 애플리케이션 간의 통신을 위한 표준 인터페이스 - 엔드포인트를 async def로 작성하면 await 가능한 호출을 논블로킹으로 처리
- 웹소켓/스트리밍에도 기본적으로 강함
- FastAPI는 WSGI(동기) 대신 ASGI(비동기) 스택(Starlette + Uvicorn)을 사용
3. 개발 환경
이 글은 Windows 유저가 쓴 글이기 때문에 Windows 기준으로 작성되었음을 미리 알립니다.
- Shell: Git Bash(MINGW64) 또는 PowerShell
- IDE: VS Code
- Python: 3.13.7
4. 가상환경 설정
가상환경?
프로젝트의 패키지 버전 충돌을 막고 의존성 일치를 보장하기 위해 가상환경을 사용함!
- 독립된 개발 환경 구성 가능
- 협업시 버전 관리에 용이함
언어는 다르지만 Spring Boot에서 사용되는 일종의 의존성이나 버전관리 용도인 pom.xml이나 build.gradle과 유사하다고 할 수 있음.
가상환경 설정하기
- 프로젝트 루트 폴더로 이동해 가상환경을 설정한다.
방법으로 가상환경 .venv를 설정해주면 구조는 다음과 같다.
1
2
3
4
5
6
venvproj/ # 루트폴더
├─ .venv/ # 가상환경
└─ app/
├─ __init__.py
└─ main.py
루트 폴더에서 가상환경 설정해야 함!!
루트에서 가상환경을 설정해야 한다. 잘못된 경로에 하지 않도록 주의하자!
1
2
3
4
5
cd ../venvproj # 루트 폴더로 이동
python -m venv .venv #.venv라는 가상환경 생성
# (선택) 특정 버전으로 만들고 싶다면
# py -3.12 -m venv .venv
.venv의 가상환경을 실행하기 위해서 venv의 Scripts를 활성화 해주면 된다.
활성화되면 프롬포트 앞에 (.venv)표시 생김
1
2
source .venv/Scripts/activate # 활성화
deactivate # 비활성화
정상 동작 확인
1
2
3
4
python -V
pip -V
python -c "import sys; print(sys.executable)"
# 출력 경로에 .../exproj/.venv/ 가 포함되어 있으면 OK
기본 패키지 설치
pip를 최신 버전으로 설치하고, FastAPI 서버를 위한 최소 패키지 설치
1
2
python -m pip install -U pip
python -m pip install fastapi "uvicorn[standard]"
- uvicorn[standard]: FastAPI 앱을 실행하는 ASGI 서버
5. app 폴더 설정
루트 경로 밑에 app 폴더를 생성한다. 여기서 파이썬 코드(엔드포인트), 라우터, 예제(JSON)를 관리한다.
디렉터리 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
exproj/
├─ .venv/
└─ app/
├─ __init__.py
├─ main.py
├─ routers/
│ ├─ __init__.py
│ └─ example.py
└─ examples/
├─ spending_series.json
├─ advice.json
└─ index.html
파일 생성은 명령어를 사용해도 되고, 직접 생성해도 된다.
1
2
3
mkdir -p app/routers app/examples
:> app/__init__.py
:> app/routers/__init__.py
아래 코드를 추가한 뒤 서버를 실행해 잘 작동하는지 확인하자~!
app/main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import os
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.routers import example ## 라우터 import
# 환경변수로 API prefix와 CORS 허용 오리진을 제어
API_PREFIX = os.getenv("API_AI_PREFIX", "/v1")
app = FastAPI(title="Ohgoodpay ML", version="0.1.0")
# CORS 설정
app.add_middleware(
CORSMiddleware,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 예시: example.py 파일에 작성한 라우터
app.include_router(example.router, prefix=API_PREFIX, tags=["example"])
# 간단 핑 엔드포인트
@app.get(API_PREFIX + "/ping")
def ping():
return {"service": "ohgoodpay-ai", "status": "ok"}
app/routers/example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from fastapi import APIRouter, HTTPException
from fastapi.responses import HTMLResponse, JSONResponse
from pathlib import Path
import json
router = APIRouter()
EXAMPLES_DIR = Path(__file__).resolve().parents[1] / "examples" # app/examples
def read_json(name: str):
p = EXAMPLES_DIR / name
if not p.exists():
raise HTTPException(404, f"Not found: {p}")
text = p.read_text(encoding="utf-8-sig").strip() # BOM 허용 + 공백 제거
if not text:
raise HTTPException(500, f"{p.name} is empty")
try:
return JSONResponse(json.loads(text))
except json.JSONDecodeError as e:
raise HTTPException(500, f"JSON parse error in {p.name}: line {e.lineno}, col {e.colno} - {e.msg}")
@router.get("/example", response_class=HTMLResponse)
def example_page():
idx = EXAMPLES_DIR / "index.html"
return idx.read_text(encoding="utf-8") if idx.exists() else "<h1>example</h1>"
@router.get("/example/spending/series")
def example_spending_series():
return read_json("spending_series.json")
@router.get("/example/advice")
def example_advice():
return read_json("advice.json")
app/examples/spending_series.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"userId": "ex",
"groupBy": "category",
"labels": ["식비","교통","쇼핑","구독"],
"values": [430000, 120000, 310000, 45000],
"trend": {
"x": ["2025-06","2025-07","2025-08"],
"series": {
"식비": [120000,140000,170000],
"쇼핑": [80000,110000,120000]
}
}
}
app/examples/advice.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"summary": "쇼핑 카테고리 비중이 높습니다.",
"insights": [
{"title": "쇼핑 집중", "detail": "전체 BNPL의 52%가 쇼핑에서 발생", "impact": "down"},
{"title": "구독 자동결제", "detail": "BNPL 구독 3건 → 월 3.2만원", "impact": "neutral"}
],
"actions": [
"월 상한 15만원 설정",
"장바구니 10만원 초과시 알림",
"구독 1건 해지로 월 1.1만원 절감"
]
}
화면을 위한 간단한 html 작성
app/examples/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>Ohgoodpay AI example</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
.card { padding: 1rem; border: 1px solid #eee; border-radius: 12px; max-width: 720px; }
ul { line-height: 1.9; }
code { background:#f6f8fa; padding:.1rem .35rem; border-radius:6px; }
</style>
</head>
<body>
<h1>Ohgoodpay AI example</h1>
<p class="card">
다음 엔드포인트로 예시 데이터를 확인하세요.
<ul>
<li><a href="/docs">/docs</a> (OpenAPI)</li>
<li><a href="/v1/example/advice/series">/v1/example/advice</a></li>
<li><a href="/v1/example/spending/series">/v1/example/spending/series</a></li>
</ul>
</p>
</body>
</html>
6. 서버 연동 확인
위의 설정이 완료되었으면 서버 실행 후 아래 엔드포인트로 접근해보자.
http://localhost:8000/v1/example
이전에 설정한 html화면이 나오면
서버 연결이 잘 된 것을 확인할 수 있다.
각 라우터 경로 확인
우선 advice와 spending/series로 각각 진입해보면
advice.json 설정 화면이 나오고,

spending_series.json 설정 화면이 나온다.

docs
마지막으로 /docs 엔드포인트로 접근하면,
Swagger ui가 나오면서 간단하게 API 테스트를 진행할 수 있다!

하나만 예시로 확인해보자, Try it out 을 눌러, Execute해보면
아래와 같이 API 테스트가 진행됨을 확인할 수 있다!!

주의
uvicorn not found → venv 활성화 후 python -m uvicorn …
ModuleNotFoundError: app → 루트에서 실행 + app/init.py 확인
마무리
로컬에서 FastAPI + Swagger를 확인하는 최소 환경을 완성했다. 남은 건 비즈니스 로직과 LLM 연동🫡
다음 글에서 이어가도록 하겠다. 빨리 오겠음.

