FastAPI - Websockets



A WebSocket is a persistent connection between a client and server to provide bidirectional, full-duplex communication between the two. The communication takes place over HTTP through a single TCP/IP socket connection. It can be seen as an upgrade of HTTP instead of a protocol itself.

One of the limitations of HTTP is that it is a strictly half-duplex or unidirectional protocol. With WebSockets, on the other hand, we can send message-based data, similar to UDP, but with the reliability of TCP. WebSocket uses HTTP as the initial transport mechanism, but keeps the TCP connection alive the connection after the HTTP response is received. Same connection object it can be used two-way communication between client and server. Thus, real-time applications can be built using WebSocket APIs.

FastAPI supports WebSockets through WebSocket class in FastAPI module. Following example demonstrates functioning of WebSocket in FastAPI application.

First we have an index() function that renders a template (socket.html). It is bound to "/" route. The HTML file socket.html is placed in the “templates” folder.

main.py

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
   return templates.TemplateResponse("socket.html", {"request": request})

The template file renders a text box and a button.

socket.html

<!DOCTYPE html>
<html>
   <head>
      <title>Chat</title>
      <script src="{{ url_for('static', path='ws.js') }}"></script>
   </head>
   <body>
      <h1>WebSocket Chat</h1>
      <form action="" onsubmit="sendMessage(event)">
      <input type="text" id="messageText" autocomplete="off"/>
      <button>Send</button>
      </form>
      <ul id='messages'>
      </ul>
   </body>
</html>

Inside the socket.html, there is a call to the JavaScript function to be executed on the form’s submit. Hence, to serve JavaScript, the "static" folder is first mounted. The JavaScript file ws.js is placed in the "static" folder.

ws.js

var ws = new WebSocket("ws://localhost:8000/ws");
ws.onmessage = function(event) {
   var messages = document.getElementById('messages')
   var message = document.createElement('li')
   var content = document.createTextNode(event.data)
   message.appendChild(content)
   messages.appendChild(message)
};
function sendMessage(event) {
   var input = document.getElementById("messageText")
   ws.send(input.value)
   input.value = ''
   event.preventDefault()
}

As the JavaScript code is loaded, it creates a websocket listening at "ws://localhost:8000/ws". The sendMessage() function directs the input message to the WebSocket URL.

This route invokes the websocket_endpoint() function in the application code. The incoming connection request is accepted and the incoming message is echoed on the client browser. Add the below code to main.py.

from fastapi import WebSocket
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
   await websocket.accept()
   while True:
      data = await websocket.receive_text()
      await websocket.send_text(f"Message text was: {data}")

Save the FastAPI code file (main.py), template (socket.html) and JavaScript file (ws.js). Run the Uvicorn server and visit http://localhost:8000/ to render the chat window as below −

FastAPI Websockets

Type a certain text and press Send button. The input message will be redirected on the browser through the websocket.

FastAPI Websockets
Advertisements