반응형
FastAPI 실시간 대화방 예제
글. 수알치 오상문
FastAPI를 이용하여 실시간 채팅 애플리케이션을 구현합니다. 사용자가 메시지를 입력하고 전송하면 서버로 전송되고, 서버는 모든 클라이언트에게 메시지를 전달(브로드캐스트)합니다.
[ FastAPI ]
/send 엔드포인트는 POST 요청으로 메시지를 받아 message_history에 저장하고, 간단한 응답을 반환합니다.
/ws 엔드포인트는 WebSocket 연결을 처리하고, 새로운 메시지가 message_history에 추가될 때마다 모든 클라이언트에게 전송합니다.
[ HTML ]
• HTMX의 hx-post, hx-target, hx-swap 속성을 사용하여 메시지 전송 폼을 처리합니다.
• JavaScript 코드는 WebSocket을 통해 서버에 연결하고, 서버에서 전송된 메시지를 chatbox에 추가합니다.
준비:
1. pip install fastapi uvicorn jinja2 htmx
2. main.py 작성
3. templates 폴더를 만들고 그곳에 index.html 파일 저장
실행:
uvicorn main:app --reload
웹브라우저에서 http://localhost:8000에 접속하여 대화를 시작합니다.
별도 탭이나 다른 브라우저에서 접속하면 서로 대화를 나눌 수 있습니다.
[ main.py ]
import asyncio
from fastapi import FastAPI, Request, Response, WebSocket, WebSocketDisconnect
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
app = FastAPI()
templates = Jinja2Templates(directory="templates")
# 채팅 메시지 저장
class Message:
def __init__(self, username: str, message: str):
self.username = username
self.message = message
connected_clients = set()
message_queue = asyncio.Queue() # 메시지 큐 사용
@app.get("/", response_class=HTMLResponse)
async def get(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
@app.post("/send")
async def send_message(request: Request):
form = await request.form()
username = form.get("username")
message = form.get("message")
await message_queue.put(Message(username, message)) # 메시지를 큐에 추가
return Response(status_code=204) # 204 No Content 응답 반환
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
connected_clients.add(websocket)
try:
while True:
message = await message_queue.get() # 큐에서 메시지 가져오기
# 모든 클라이언트에게 메시지 전송
for client in connected_clients:
await client.send_json({"username": message.username, "message": message.message})
except WebSocketDisconnect:
connected_clients.remove(websocket)
[ index.html ]
<!DOCTYPE html>
<html>
<head>
<title>FastAPI 실시간 채팅</title>
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
<style>
/* 채팅 상자 스타일 */
#chatbox {
width: 400px;
height: 300px;
overflow-y: scroll;
border: 1px solid #ccc;
padding: 10px;
}
input[name="username"] {
width: 80px; /* username 입력 필드 너비 */
}
input[name="message"] {
width: 260px; /* message 입력 필드 너비 */
}
</style>
</head>
<body>
<h1>아무나 대화방</h1>
<div id="chatbox">
</div>
<form hx-post="/send" hx-target="#chatbox" hx-swap="beforeend" hx-trigger="submit">
<input type="text" name="username" placeholder="이름">
<input type="text" name="message" placeholder="메시지">
<button type="submit">전송</button>
</form>
<script>
// 웹소켓 연결
const websocket = new WebSocket("ws://localhost:8000/ws");
websocket.onmessage = function(event) {
const message = JSON.parse(event.data);
const chatbox = document.getElementById("chatbox");
const messageElement = document.createElement("p");
messageElement.textContent = `${message.username}: ${message.message}`;
chatbox.appendChild(messageElement);
// 새로운 메시지가 추가될 때 스크롤을 맨 아래로 이동
chatbox.scrollTop = chatbox.scrollHeight;
// 메시지 전송 후 입력 필드 초기화
document.querySelector('input[name="message"]').value = '';
}
</script>
</body>
</html>
[화면] 대화를 나누는 모습
반응형
'FastAPI' 카테고리의 다른 글
FastAPI 테스트 (with pytest) (0) | 2025.01.05 |
---|---|
(SQLAlechemy 보다 편리한) SQLModel + FastAPI 이용 (0) | 2024.12.29 |
SQLAlchemy, 객체 값 업데이트 setattr () (0) | 2024.12.19 |
FastAPI, Jinja 기본 예제 (2) | 2024.12.18 |
FastAPI, CRUD API 예제 (0) | 2024.12.17 |