How do you create WebSocket endpoints in FastAPI?
FastAPI provides WebSocket support through Starlette's WebSocket class. You define WebSocket endpoints using the @app.websocket() decorator instead of the usual @app.get() or @app.post().
How it works:
- Decorate an async function with
@app.websocket("/path") - The function receives a
WebSocketobject as its first parameter - Call
await websocket.accept()to complete the handshake - Use
await websocket.receive_text()orreceive_bytes()to read messages - Use
await websocket.send_text()orsend_bytes()to send messages - Close with
await websocket.close()
Key differences from HTTP endpoints:
- WebSocket endpoints are persistent connections, not request-response
- They do not return a value -- communication happens through the
websocketobject - Path parameters and query parameters still work
- Response models and status codes do not apply
Path parameters and query parameters:
WebSocket endpoints support the same path and query parameter extraction as regular endpoints. You can use type annotations and FastAPI will validate them.
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
from fastapi import FastAPI, WebSocket
import asyncio
app = FastAPI()
# --- Basic WebSocket endpoint ---
@app.websocket("/ws")
async def websocket_echo(websocket: WebSocket):
"""Simple echo server -- sends back whatever it receives."""
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
# --- With path parameters ---
@app.websocket("/ws/rooms/{room_id}")
async def room_websocket(
websocket: WebSocket,
room_id: int,
):
"""Path parameters work just like HTTP endpoints."""
await websocket.accept()
await websocket.send_text(f"Connected to room {room_id}")
while True:
data = await websocket.receive_text()
await websocket.send_text(f"[Room {room_id}] {data}")
# --- With query parameters ---
@app.websocket("/ws/chat")
async def chat_websocket(
websocket: WebSocket,
username: str = "anonymous",
):
"""Query parameters extracted from the ws:// URL."""
await websocket.accept()
await websocket.send_text(f"Welcome, {username}!")
while True:
message = await websocket.receive_text()
await websocket.send_text(f"{username}: {message}")
# --- Client-side JavaScript example ---
# const ws = new WebSocket("ws://localhost:8000/ws/chat?username=alice");
# ws.onmessage = (event) => console.log(event.data);
# ws.onopen = () => ws.send("Hello!");
- •Use @app.websocket("/path") to define WebSocket endpoints
- •Always call await websocket.accept() before sending or receiving
- •Path and query parameters work identically to HTTP endpoints
- •WebSocket endpoints are long-lived -- they run until the connection closes or an error occurs
- •WebSocket endpoints cannot use response_model or status_code -- they communicate through the WebSocket object directly
- •Forgetting to call websocket.accept() will leave the client hanging with no handshake completion
- •A bare while True loop will run forever if the client disconnects without sending a close frame -- always handle WebSocketDisconnect
- •WebSocket URLs use ws:// or wss:// scheme, not http:// or https://