p2h: add WebSockets & SSE tutorial — echo server, broadcast, event stream, comparison table
swadhinbiswas committed 3 months ago
f86644e
1 parent fccffe6
commit f86644e
1 file changed
+144 -0
Showing 1 changed file+144-0
▼docs_site/src/content/docs/tutorials/websockets-sse.md
+144-0
| @@ -0,0 +1,144 @@ | ||
1 | +--- | |
2 | +title: WebSockets & Server-Sent Events | |
3 | +description: Build real-time applications with WebSockets and SSE streaming. | |
4 | +--- | |
5 | + | |
6 | +JustAPI supports both WebSockets (full-duplex) and Server-Sent Events (server-to-client streaming) for real-time communication. | |
7 | + | |
8 | +## WebSockets | |
9 | + | |
10 | +### Echo Server | |
11 | + | |
12 | +```python | |
13 | +from justapi import JustAPIApp | |
14 | + | |
15 | +app = JustAPIApp() | |
16 | + | |
17 | + | |
18 | +@app.websocket("/ws") | |
19 | +async def echo(ws): | |
20 | + await ws.accept() | |
21 | + try: | |
22 | + while True: | |
23 | + data = await ws.receive_text() | |
24 | + await ws.send_text(f"Echo: {data}") | |
25 | + except Exception: | |
26 | + print("Client disconnected") | |
27 | +``` | |
28 | + | |
29 | +### Test with a WebSocket Client | |
30 | + | |
31 | +```bash | |
32 | +# Using websocat | |
33 | +websocat ws://127.0.0.1:8000/ws | |
34 | +> Hello | |
35 | +< Echo: Hello | |
36 | +``` | |
37 | + | |
38 | +Or from JavaScript: | |
39 | + | |
40 | +```javascript | |
41 | +const ws = new WebSocket("ws://localhost:8000/ws"); | |
42 | +ws.onmessage = (event) => console.log(event.data); | |
43 | +ws.send("Hello"); | |
44 | +``` | |
45 | + | |
46 | +### WebSocket API Reference | |
47 | + | |
48 | +| Method | Description | | |
49 | +|---|---| | |
50 | +| `await ws.accept()` | Accept the WebSocket upgrade | | |
51 | +| `await ws.receive_text()` | Receive a text message | | |
52 | +| `await ws.receive_bytes()` | Receive a binary message | | |
53 | +| `await ws.receive_json()` | Receive and parse a JSON message | | |
54 | +| `await ws.send_text(data)` | Send a text message | | |
55 | +| `await ws.send_bytes(data)` | Send a binary message | | |
56 | +| `await ws.send_json(data)` | Send a JSON message | | |
57 | +| `await ws.close()` | Close the connection | | |
58 | + | |
59 | +### Broadcasting to Multiple Clients | |
60 | + | |
61 | +```python | |
62 | +import asyncio | |
63 | + | |
64 | +connected = set() | |
65 | + | |
66 | + | |
67 | +@app.websocket("/chat") | |
68 | +async def chat(ws): | |
69 | + await ws.accept() | |
70 | + connected.add(ws) | |
71 | + try: | |
72 | + while True: | |
73 | + data = await ws.receive_text() | |
74 | + # Broadcast to all connected clients | |
75 | + for client in connected: | |
76 | + if client != ws: | |
77 | + await client.send_text(data) | |
78 | + finally: | |
79 | + connected.discard(ws) | |
80 | +``` | |
81 | + | |
82 | +## Server-Sent Events (SSE) | |
83 | + | |
84 | +SSE streams events from server to client over a single HTTP connection: | |
85 | + | |
86 | +```python | |
87 | +import asyncio | |
88 | +from justapi.responses import StreamingResponse | |
89 | + | |
90 | + | |
91 | +@app.get("/events") | |
92 | +async def event_stream(request): | |
93 | + async def generate(): | |
94 | + for i in range(10): | |
95 | + yield f"data: Event #{i}\n\n" | |
96 | + await asyncio.sleep(1) | |
97 | + | |
98 | + return StreamingResponse(generate(), media_type="text/event-stream") | |
99 | +``` | |
100 | + | |
101 | +```bash | |
102 | +curl -N http://127.0.0.1:8000/events | |
103 | +# Output: | |
104 | +# data: Event #0 | |
105 | +# data: Event #1 | |
106 | +# ... | |
107 | +``` | |
108 | + | |
109 | +### SSE with JSON Data | |
110 | + | |
111 | +```python | |
112 | +import json | |
113 | +import asyncio | |
114 | +import random | |
115 | +from justapi.responses import StreamingResponse | |
116 | + | |
117 | + | |
118 | +@app.get("/stock-prices") | |
119 | +async def stock_prices(request): | |
120 | + async def generate(): | |
121 | + while True: | |
122 | + price = {"symbol": "JUST", "price": round(100 + random.random() * 10, 2)} | |
123 | + yield f"data: {json.dumps(price)}\n\n" | |
124 | + await asyncio.sleep(0.5) | |
125 | + | |
126 | + return StreamingResponse(generate(), media_type="text/event-stream") | |
127 | +``` | |
128 | + | |
129 | +## Choosing Between WebSockets and SSE | |
130 | + | |
131 | +| Feature | WebSocket | SSE | | |
132 | +|---|---|---| | |
133 | +| Direction | Bidirectional | Server → Client only | | |
134 | +| Protocol | `ws://` / `wss://` | Standard HTTP | | |
135 | +| Message format | Text or binary | Text-only (usually JSON) | | |
136 | +| Auto-reconnect | Manual | Built-in (EventSource API) | | |
137 | +| Browser support | All modern browsers | All modern browsers | | |
138 | +| Use case | Chat, gaming, collaboration | Live updates, notifications, feeds | | |
139 | + | |
140 | +## Next Steps | |
141 | + | |
142 | +- [Background Tasks](/tutorials/background-tasks/) — Async tasks after response | |
143 | +- [Streaming Output](/advanced/streaming-output/) — Validated streaming with Rust | |
144 | +- [Agent System](/advanced/agent-system/) — Sessions and MCP tools | |
0 | 145 | |