C.W.K.
Stream
Lesson 03 of 08 · published

Echo Server

~10 min · fastapi, echo, html-test-page

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

A complete loopback server

Tying together the previous two lessons: a complete echo server that wraps every message in a small envelope (timestamp, server name, type) and serves a tiny HTML test page on / from the same FastAPI app. Useful as a sanity-check sandbox while you build out application logic.

Why the HTML page

Browsers will refuse ws:// from https:// pages, and many corporate proxies block raw ws:// entirely. Serving the test client from the same origin sidesteps both. cwkPippa does the same trick — the React UI and the FastAPI backend live on adjacent ports during development, and the production deploy puts them on a single origin.

Code

Self-contained echo + test page·python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from datetime import datetime

app = FastAPI()

@app.websocket('/ws')
async def echo(websocket: WebSocket):
    await websocket.accept()
    await websocket.send_json({
        'type': 'system',
        'message': 'connected to echo',
        'ts': datetime.now().isoformat(),
    })
    try:
        async for msg in websocket.iter_json():
            await websocket.send_json({
                'type': 'echo',
                'original': msg,
                'ts': datetime.now().isoformat(),
                'server': 'fastapi-echo-v1',
            })
    except WebSocketDisconnect:
        # Client closed; nothing to clean up here yet.
        pass

@app.get('/')
async def index():
    return HTMLResponse('''
<!doctype html><html><body>
<input id=msg placeholder="type and Enter">
<pre id=log></pre>
<script>
  const log = document.getElementById('log');
  const ws = new WebSocket('ws://' + location.host + '/ws');
  ws.onmessage = e => log.textContent += e.data + '\n';
  document.getElementById('msg').addEventListener('keydown', e => {
    if (e.key === 'Enter') {
      ws.send(JSON.stringify({ text: e.target.value }));
      e.target.value = '';
    }
  });
</script>
</body></html>''')

External links

Exercise

Run the self-contained echo server. Open http://localhost:8000/ in a browser. Send five messages and verify the envelope shape in the log. Now disconnect by closing the tab and reconnect — confirm the server logs WebSocketDisconnect cleanly without traceback.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.