WebSocket 실시간 채팅: FastAPI + SvelteKit 구현 완전 가이드
실시간 채팅은 현대 웹 애플리케이션의 핵심 기능 중 하나입니다. HTTP 요청-응답 방식과 달리, WebSocket은 서버와 클라이언트 간 양방향 통신을 지속적으로 유지해 지연 없는 메시지 전달을 가능하게 합니다. 이 글에서는 Python 백엔드 프레임워크 FastAPI와 풀스택 프론트엔드 프레임워크 SvelteKit을 조합하여 실시간 채팅 애플리케이션을 처음부터 구현하는 방법을 소개합니다.
왜 FastAPI + SvelteKit인가?
| 항목 | FastAPI | SvelteKit |
|---|---|---|
| 언어 | Python | JavaScript / TypeScript |
| 비동기 처리 | asyncio 기반 네이티브 지원 | 서버 액션 + 클라이언트 반응성 |
| WebSocket | 내장 지원 | 브라우저 WebSocket API 활용 |
| 성능 | Node.js급 고성능 | 컴파일 기반 최소 번들 |
| 학습 곡선 | 완만 (자동 문서화 포함) | 완만 (Svelte 문법 직관적) |
| 실시간 UI | 서버 측 브로드캐스트 | 반응형 상태 자동 업데이트 |
두 프레임워크 모두 개발자 경험(DX)이 뛰어나고, 서로 REST/WebSocket API로 자연스럽게 연동됩니다.
프로젝트 구조
chat-app/
├── backend/
│ ├── main.py
│ └── requirements.txt
└── frontend/
├── src/
│ └── routes/
│ └── +page.svelte
└── package.json
Step 1: FastAPI 백엔드 구현
패키지 설치
pip install fastapi uvicorn websockets
ConnectionManager 구현
다중 클라이언트 연결을 관리하는 핵심 클래스입니다.
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from typing import List
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
await manager.broadcast(f"{client_id}: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
await manager.broadcast(f"{client_id} 님이 채팅방을 나갔습니다.")
서버 실행
uvicorn main:app --reload --port 8000
Step 2: SvelteKit 프론트엔드 구현
프로젝트 생성
npm create svelte@latest frontend
cd frontend
npm install
채팅 페이지 구현 (src/routes/+page.svelte)
<script lang="ts">
import { onMount, onDestroy } from "svelte";
let ws: WebSocket;
let messages: string[] = [];
let inputText = "";
const clientId = Math.random().toString(36).substring(2, 7);
onMount(() => {
ws = new WebSocket(`ws://localhost:8000/ws/${clientId}`);
ws.onmessage = (event) => {
messages = [...messages, event.data];
};
ws.onclose = () => {
console.log("연결 종료");
};
});
onDestroy(() => {
if (ws) ws.close();
});
function sendMessage() {
if (ws.readyState === WebSocket.OPEN && inputText.trim()) {
ws.send(inputText);
inputText = "";
}
}
</script>
<main>
<h1>실시간 채팅 - {clientId}</h1>
<div class="messages">
{#each messages as msg}
<p>{msg}</p>
{/each}
</div>
<form on:submit|preventDefault={sendMessage}>
<input bind:value={inputText} placeholder="메시지를 입력하세요..." />
<button type="submit">전송</button>
</form>
</main>
Step 3: 채팅방(Room) 기능 추가
실서비스에서는 여러 채팅방이 필요합니다. 아래는 방별 연결을 관리하는 확장 구현입니다.
from collections import defaultdict
class RoomManager:
def __init__(self):
self.rooms: dict = defaultdict(list)
async def join(self, room: str, websocket: WebSocket):
await websocket.accept()
self.rooms[room].append(websocket)
def leave(self, room: str, websocket: WebSocket):
self.rooms[room].remove(websocket)
async def broadcast_room(self, room: str, message: str):
for conn in self.rooms[room]:
await conn.send_text(message)
room_manager = RoomManager()
@app.websocket("/ws/{room}/{client_id}")
async def room_endpoint(websocket: WebSocket, room: str, client_id: str):
await room_manager.join(room, websocket)
try:
while True:
data = await websocket.receive_text()
await room_manager.broadcast_room(room, f"[{room}] {client_id}: {data}")
except WebSocketDisconnect:
room_manager.leave(room, websocket)
Step 4: 배포 고려 사항
운영 환경에서는 다음 요소를 반드시 점검해야 합니다.
- Nginx WebSocket 프록시: proxy_pass와 함께 Upgrade 헤더 설정 필요
- Gunicorn + Uvicorn workers: 멀티코어 활용을 위해 gunicorn -k uvicorn.workers.UvicornWorker 사용
- Redis Pub/Sub: 여러 서버 인스턴스 간 메시지 동기화를 위해 Redis 브로드캐스트 채널 사용
- JWT 인증: WebSocket 핸드셰이크 시 쿼리 파라미터로 토큰 전달 후 검증
- 재연결 로직: 클라이언트에서 지수 백오프(exponential backoff) 방식으로 자동 재연결 구현
정리
FastAPI의 비동기 WebSocket 지원과 SvelteKit의 반응형 UI를 결합하면, 복잡한 라이브러리 없이도 완성도 높은 실시간 채팅을 구현할 수 있습니다. ConnectionManager 패턴으로 연결을 체계적으로 관리하고, Svelte의 반응성으로 메시지가 도착하는 즉시 화면에 반영됩니다.
코드벤터는 FastAPI와 SvelteKit 기반의 실무 프로젝트 경험을 바탕으로, 실시간 기능이 필요한 서비스 개발을 지원합니다. WebSocket 아키텍처 설계부터 배포까지 전 과정을 함께할 수 있으니, 프로젝트가 있다면 언제든지 코드픽(codepick.kr)에서 전문가를 찾아보세요.