<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ websockets - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ websockets - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 22:37:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/websockets/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use WebSockets: From Python to FastAPI ]]>
                </title>
                <description>
                    <![CDATA[ Real-time data powers much of modern software: live stock prices, chat applications, sports scores, collaborative tools. And to build these systems, you'll need to understand how real-time communicati ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-websockets-from-python-to-fastapi/</link>
                <guid isPermaLink="false">69b206806c896b0519d2a308</guid>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ FastAPI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Backend Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Real Time ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nneoma Uche ]]>
                </dc:creator>
                <pubDate>Thu, 12 Mar 2026 00:19:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/8acb0854-7289-4794-8f97-242ec5d8ca61.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Real-time data powers much of modern software: live stock prices, chat applications, sports scores, collaborative tools. And to build these systems, you'll need to understand how real-time communication actually works—which isn’t always straightforward.</p>
<p>I ran into this firsthand while trying to build a live options dashboard. HTTP requests weren't going to cut it, and everything I was reading seemed overly complex until I went back to the basics. This article is the result of that process.</p>
<p>We'll cover Python's <code>websockets</code> library from scratch, then move into FastAPI, where many Python backends live. It's worth noting that WebSockets aren't the only solution for real-time communication. WebRTC may be a better fit depending on your use case, but understanding WebSockets is the right starting point before exploring further.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ol>
<li><p><a href="#heading-websocket-connections-and-methods">WebSocket Connections and Methods</a></p>
</li>
<li><p><a href="#heading-how-to-build-your-first-websocket-in-python">How to Build Your First WebSocket in Python</a></p>
</li>
<li><p><a href="#heading-file-transfer-over-websockets">File Transfer Over WebSockets</a></p>
</li>
<li><p><a href="#heading-how-to-connect-to-an-external-websocket">How to Connect to an External WebSocket</a></p>
</li>
<li><p><a href="#heading-websockets-in-fastapi">WebSockets in FastAPI</a></p>
</li>
<li><p><a href="#heading-how-to-handle-websocket-disconnections-in-fastapi">How to Handle WebSocket Disconnections in FastAPI</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-websocket-connections-and-methods">WebSocket Connections and Methods</h2>
<p>A WebSocket connection enables bi-directional communication between a client and a server. Once a connection is established, both sides can communicate freely without either having to ask first. This is different from a regular HTTP request, where the client always has to ask before the server can respond.</p>
<p>It looks something like this:</p>
<pre><code class="language-plaintext">        CLIENT&nbsp; &lt;===== open connection =====&gt;&nbsp; SERVER
</code></pre>
<p>Note that a WebSocket URL is not a regular web page, so you can't "visit it" like a website. You need a client to talk to it.</p>
<p>Different frameworks provide different methods for handling WebSocket connections. With Python’s <code>websockets</code> library, for instance, a connection is automatically accepted the moment a client connects. With frameworks like FastAPI, you have to explicitly call <code>await websocket.accept()</code>, otherwise the connection gets rejected.</p>
<p>Let’s look at the core methods provided by Python’s <code>websockets</code> library:</p>
<ol>
<li><p><code>websockets.serve(...)</code>:&nbsp; starts a WebSocket server.</p>
</li>
<li><p><code>websockets.connect(...)</code>: connects to a WebSocket server.</p>
</li>
<li><p><code>websockets.send(...)</code>: sends a message from either side.</p>
</li>
<li><p><code>websockets.recv()</code>: receives a message from client or server.</p>
</li>
</ol>
<p><code>recv()</code> takes no arguments because it's purely a waiting operation. It waits for the next message and returns it:</p>
<pre><code class="language-python">message = await websocket.recv()
</code></pre>
<h2 id="heading-how-to-build-your-first-websocket-in-python">How to Build Your First WebSocket in Python</h2>
<p>Before we dive into frameworks, let’s explore Python’s <code>websockets</code> library. You’ll set up a simple server and client, and exchange messages over a WebSocket connection, giving you a solid foundation for understanding WebSockets under the hood.</p>
<h3 id="heading-environment-setup">Environment Setup</h3>
<p>Run the following in your virtual environment to install or verify the WebSockets package:</p>
<pre><code class="language-python">pip install websockets
# or, to check if it's already installed:
pip show websockets
</code></pre>
<h3 id="heading-create-the-websocket-server">Create the WebSocket Server</h3>
<p>Create <code>server.py</code> in your project folder, and paste this:</p>
<pre><code class="language-python">import asyncio
import websockets

async def handler(connection):
    print("Client connected")

    message = await connection.recv()
    print("Received from client:", message)
    await connection.send("Hello client!")


async def main():
    async with websockets.serve(handler, "localhost", 8000):
        print("Server running at ws://localhost:8000")
        #await asyncio.Future()  # runs forever
        await asyncio.sleep(30)

asyncio.run(main())
</code></pre>
<p>When this line executes:</p>
<pre><code class="language-python">async with websockets.serve(handler, "localhost", 8000):
</code></pre>
<p>The library opens a TCP socket on the specified host and port and waits for incoming clients. When one connects, it creates a connection object and passes it into your handler function.</p>
<p>The handler is required because it defines what the server does with each connection. The <code>host</code> and <code>port</code> arguments are also important. Both default to <code>None</code> – passing neither raises an error because the OS cannot bind a network server without a port.</p>
<p>You could pass <code>port=0</code> to let the OS assign a free port automatically, but then you'd need an extra step to figure out which port was chosen, so the client can connect:</p>
<pre><code class="language-python">server.sockets[0].getsockname()
</code></pre>
<p>It’s simpler to specify both host and port explicitly, so the client knows exactly where the server is running.</p>
<h3 id="heading-set-up-the-client">Set Up the Client</h3>
<p>Create <code>client.py</code> in the same folder and add this:</p>
<pre><code class="language-python">import asyncio
import websockets

async def client():
    async with websockets.connect("ws://localhost:8000") as websocket:
        await websocket.send("Hello server!")
        response = await websocket.recv()
        print("Server replied:", response)

asyncio.run(client())
</code></pre>
<h3 id="heading-test-the-connection">Test the Connection</h3>
<p>First, open a terminal and run <code>server.py</code>. You should see:</p>
<pre><code class="language-plaintext">Server running at ws://localhost:8000
</code></pre>
<p>In a second terminal, run <code>client.py</code>. Messages should appear in both terminals confirming that the connection is active and both sides are communicating.</p>
<p>Note that the server must be running before you start the client – otherwise the client has nothing to connect to, and the connection will fail.</p>
<h4 id="heading-keeping-the-server-alive-a-note-on-asynciofuture">Keeping the server alive: a note on asyncio.Future()</h4>
<p>In <code>server.py</code>, there’s a line currently commented out:</p>
<pre><code class="language-python">await asyncio.Future()
</code></pre>
<p>This keeps the server running indefinitely. For local development and testing however, <code>await asyncio.sleep(30)</code> is a simpler alternative. It keeps the server alive for a fixed period without running forever.</p>
<h2 id="heading-file-transfer-over-websockets">File Transfer Over WebSockets</h2>
<p>WebSockets aren't limited to text. They support raw bytes too, which means you can send files directly over the connection. Here’s how a client can send a file to a server over a WebSocket connection:</p>
<h3 id="heading-update-serverpy">Update <code>server.py</code></h3>
<pre><code class="language-python">async def file_handler(ws):
    print("Client connected, waiting for file...")
    file_bytes = await ws.recv()  # receive bytes
    with open("received_file.png", "wb") as f:
        f.write(file_bytes)
    print("File received and saved!")
    await ws.send("File received successfully!")

async def main():
    async with websockets.serve(file_handler, "localhost", 8000):
        print("Server running on ws://localhost:8000")
        await asyncio.sleep(50)  # keep server alive

asyncio.run(main())
</code></pre>
<p>The handler waits for incoming bytes with <code>await ws.recv()</code>; the <code>websockets</code> library automatically detects whether the incoming message is text or bytes, so no extra configuration is needed. Once received, the file is written to disk in binary mode (<code>"wb"</code>) and the server sends a confirmation message back to the client.</p>
<h3 id="heading-update-clientpy">Update <code>client.py</code></h3>
<pre><code class="language-python">import asyncio
import websockets

async def send_file():
    uri = "ws://localhost:8000"
    async with websockets.connect(uri) as ws:
        with open("portfolio-image.png", "rb") as f:  #open file in binary mode
            file_bytes = f.read()
        await ws.send(file_bytes)  # send bytes
        response = await ws.recv()
        print("Server response:", response)

asyncio.run(send_file())
</code></pre>
<p>The client opens the image in binary mode (<code>"rb"</code>), reads the entire file into memory as bytes, and sends it in a single <code>ws.send()</code> call. It then waits for the server's confirmation before closing the connection.</p>
<h3 id="heading-test-it">Test it</h3>
<p>Add an image to your project folder and make sure the filename in <code>client.py</code> matches. Run <code>server.py</code> first, then <code>client.py</code> in a second terminal.</p>
<p>Once the transfer completes, the server saves the file as <code>received_file.png</code> in the same directory. You should see it appear in your workspace immediately.</p>
<p>This approach loads the entire file into memory before sending. For large files, it’s better to read and send them in chunks. But this is the easiest way to understand WebSocket byte transfer.</p>
<h2 id="heading-how-to-connect-to-an-external-websocket">How to Connect to an External WebSocket</h2>
<p>So far you've been connecting to servers you built yourself. But WebSocket clients can also connect to public servers. For example, a client can connect to Postman’s echo server:</p>
<pre><code class="language-python">import asyncio
import websockets

async def connect_external():
    uri = "wss://ws.postman-echo.com/raw"  # public WebSocket server
    async with websockets.connect(uri) as ws:
        print("Connected to external server!")

        # Send a message
        await ws.send("Hello external server!")
        print("Message sent")

        # Receive response
        response = await ws.recv()
        print("Received from server:", response)
asyncio.run(connect_external())
</code></pre>
<p>Notice the client connects to Postman’s echo server using the <code>wss://</code> URI scheme instead of <code>ws://</code>. This indicates the connection is encrypted using TLS, similar to how <code>https://</code> secures regular web requests.</p>
<p>An echo server returns exactly what you send it. So "Hello external server!" comes straight back as the response. It's a useful sandbox for testing your client-side WebSocket code without needing your own server.</p>
<h2 id="heading-websockets-in-fastapi">WebSockets in FastAPI</h2>
<p>FastAPI provides a WebSocket object (via Starlette under the hood) to manage real-time connections. You can define WebSocket endpoints just like HTTP routes, while Uvicorn handles the event loop – no manual asyncio server management needed. This makes FastAPI a natural fit for real-time projects, from chat apps to live dashboards and data feeds.</p>
<p>Before jumping into code, here's a quick reference of the core methods you'll be working with.</p>
<p><strong>Accepting:</strong></p>
<ul>
<li><code>await websocket.accept()</code>: the <code>accept()</code> method must be called first, before anything else. Skip it and the connection gets rejected.</li>
</ul>
<p><strong>Sending:</strong></p>
<ul>
<li><p><code>await websocket.send_text(data)</code>: sends a string.</p>
</li>
<li><p><code>await websocket.send_bytes(data)</code>: sends binary data.</p>
</li>
<li><p><code>await websocket.send_json(data)</code>: serializes and sends JSON.</p>
</li>
</ul>
<p><strong>Receiving:</strong></p>
<ul>
<li><p><code>await websocket.receive_text()</code>: waits for a text message.</p>
</li>
<li><p><code>await websocket.receive_bytes()</code>: waits for binary data.</p>
</li>
<li><p><code>await websocket.receive_json()</code>: receives and deserializes JSON.</p>
</li>
<li><p><code>async for msg in websocket.iter_text()</code>: iterates over incoming messages, exits cleanly on disconnect.</p>
</li>
</ul>
<p><strong>Closing:</strong></p>
<ul>
<li><code>await websocket.close(code=1000)</code>: standard code for a normal closure. It accepts an optional “reason” argument.</li>
</ul>
<p>Here's what the WebSocket lifecycle looks like in FastAPI:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6426acfa5bc738c37852b5bd/b61b6b25-e027-47a1-8efc-b921e93b8521.png" alt="WebSocket in FastAPI" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-building-a-simple-echo-server-with-fastapi">Building a Simple Echo Server with FastAPI</h3>
<p>As you saw with the Postman example, an echo server sends back the message a client provides. Let's build one with FastAPI.</p>
<h4 id="heading-1-install-fastapi">1. Install FastAPI:</h4>
<pre><code class="language-python">pip install "fastapi[standard]"
</code></pre>
<h4 id="heading-2-update-serverpy">2. Update <code>server.py</code>:</h4>
<pre><code class="language-python">from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    data = await websocket.receive_text()
   
    await websocket.send_text(f"You said: {data}")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)
</code></pre>
<p>A few things to note here compared to the plain <code>websockets</code> library:</p>
<ul>
<li><p>WebSocket endpoints are defined with <code>@app.websocket("/ws")</code> just like an HTTP route.</p>
</li>
<li><p><code>await websocket.accept()</code> is required before anything else. FastAPI won't accept connections without it.</p>
</li>
<li><p>Uvicorn handles the event loop and server startup for you via the <code>if name == "__main__"</code> block. No <code>asyncio.run()</code> or <code>asyncio.Future()</code> needed.</p>
</li>
</ul>
<h4 id="heading-3-update-clientpy">3. Update client.py:</h4>
<pre><code class="language-python">async def test_client():
    uri = "ws://127.0.0.1:8000/ws"
    async with websockets.connect(uri) as ws:
        await ws.send("Hello FastAPI server!")
        response = await ws.recv()
        print("Server replied:", response)

asyncio.run(test_client())
</code></pre>
<p>Since the FastAPI server isn't secured with TLS, the client URI uses <code>ws://</code> instead of <code>wss://</code>. Make sure to match the host and port from your server code.</p>
<h4 id="heading-4-interact-with-the-echo-server">4. Interact with the echo server:</h4>
<p>Start <code>server.py</code>, then run <code>client.py</code> in another terminal. The server terminal should show the echoed message.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6426acfa5bc738c37852b5bd/88629d79-eb91-4af5-9752-f9596ff5e5a4.png" alt="88629d79-eb91-4af5-9752-f9596ff5e5a4" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-how-to-handle-websocket-disconnections-in-fastapi">How to Handle WebSocket Disconnections in FastAPI</h2>
<p>Clients will inevitably disconnect in real-time applications, sometimes intentionally, sometimes unexpectedly. If not handled properly, this can crash your server or leave it in a broken state.</p>
<p>The <code>WebSocketDisconnect</code> exception in FastAPI is raised whenever a client unexpectedly closes the connection, allowing the server to handle disconnects gracefully, log the event, and clean up resources without crashing.</p>
<p>Here’s an example:</p>
<pre><code class="language-python">@app.websocket("/ws")
async def websocket_endpoint(ws: WebSocket):
    await ws.accept()
    try:
        while True:
            data = await ws.receive_text()
   
            if "bye" in data or "quit" in data:
                await ws.send_text("Closing connection")
                await ws.close(code=1000, reason="Server requested close")  
                break
            await ws.send_text(f"I got your request: {data}")
    except WebSocketDisconnect:
        print("Client disconnected")  # connection already closed
</code></pre>
<p>The server runs a continuous loop waiting for messages. If the client message contains "bye" or "quit", the server responds, calls <code>await ws.close(code=1000)</code>, and breaks out of the loop cleanly.</p>
<p>But if the client disconnects unexpectedly, <code>WebSocketDisconnect</code> is caught by the except block and the server moves on without crashing. At this point the connection is already closed on the client side, so calling <code>ws.close()</code> inside the except block is unnecessary.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>WebSockets make real-time communication possible by keeping a persistent connection open between client and server. Starting with Python’s <code>websockets</code> library helps clarify how the protocol works under the hood, while frameworks like FastAPI provide the structure needed for production applications.</p>
<p>The parts that trip most people up early on are <code>asyncio</code> and FastAPI's explicit <code>websocket.accept()</code>. With <code>asyncio</code>, the question is usually why it's needed and why the server dies instantly without something keeping it alive. And it's easy to ignore <code>websocket.accept()</code> if you're coming from the plain <code>websockets library</code> where that happens automatically. Once those click, everything else follows naturally.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Real-Time Systems for Web Developers: From Theory to a Live Go + React App ]]>
                </title>
                <description>
                    <![CDATA[ Many developers think that “real-time” is about Websockets, Live data, or instant refreshes on web application dashboards. And although these concepts are closely related to what real-time means, the systems engineering definition is a bit different.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/real-time-systems-for-web-developers-from-theory-to-a-live-go-react-app/</link>
                <guid isPermaLink="false">695e96b3ee29df356daaf7c0</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ realtime apps ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Emmanuel Etukudo ]]>
                </dc:creator>
                <pubDate>Wed, 07 Jan 2026 17:24:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767748231282/074fcd8b-8808-4a3d-8c9c-17d5a7b388e6.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Many developers think that “real-time” is about Websockets, Live data, or instant refreshes on web application dashboards.</p>
<p>And although these concepts are closely related to what real-time means, the systems engineering definition is a bit different. A real-time system is not defined by how fast it is, but how predictable it is. </p>
<p>In this tutorial, you’ll learn about what real-time systems are, why most web applications are not real-time, and how to build a <strong>soft real-time system</strong> with tools you’re likely already familiar with: Go, React, and TypeScript.</p>
<p>At the end of this tutorial, we’ll build a live application that:</p>
<ul>
<li><p>processes time-sensitive events</p>
</li>
<li><p>enforces deadlines</p>
</li>
<li><p>drops work when it’s too late </p>
</li>
<li><p>and visualises latency and missed deadlines in real-time</p>
</li>
</ul>
<p>  This article will help shape your mind the next time you’re building a real-time system.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-a-real-time-system-really-means">What a Real-Time System Really Means</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-types-of-real-time-systems">Types of Real-Time Systems</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-most-web-apps-are-not-real-time">Why Most Web Apps Are Not Real-Time</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-we-are-going-to-build">What We Are Going to Build</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-system-architecture">System Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-go-is-a-good-fit-for-our-use-case">Why Go is a Good Fit for Our Use Case</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-generating-events-with-go">Generating Events with Go</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-deadline-aware-processing">Deadline-aware Processing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-applying-back-pressure">Applying Back-Pressure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-streaming-events-to-the-browser">Streaming Events to the Browser</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-consuming-a-websocket-event-react-typescript">Consuming a WebSocket event (React + TypeScript)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-making-react-real-time-friendly">Making React Real-Time Friendly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-creating-the-statsbar-component">Creating the StatsBar Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-creating-the-events-table">Creating the Events Table</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-putting-it-all-together">Putting it All Together</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This tutorial assumes that you have basic knowledge of <code>Go</code>, <code>React</code>, and <code>WebSockets</code>, particularly working with go-routines and consuming <code>WebSockets</code> events in <code>React</code>. If you don’t, I strongly recommend reviewing introductory tutorials before continuing so you can get the most out of this guide.  </p>
<p>Helpful references include:</p>
<ul>
<li><p><strong>Go Concurrency and Goroutines:</strong> The official Go blog covers concurrency patterns, including goroutines and channels, which are <a target="_blank" href="https://go.dev/blog/concurrency-patterns">fundamental for writing concurrent Go code</a>.</p>
</li>
<li><p><strong>WebSockets with Go:</strong> A thorough WebSocket tutorial using the popular gorilla/websocket package that shows how to set up a WebSocket server in Go and manage connections and messages. <a target="_blank" href="https://tutorialedge.net/golang/go-websocket-tutorial">Here’s a Go WebSocket tutorial (with gorilla/websocket)</a>.</p>
</li>
<li><p><strong>WebSockets in React:</strong> A complete guide to WebSockets in React, explaining how to open and manage a WebSocket connection and handle incoming messages in components. <a target="_blank" href="https://ably.com/blog/websockets-react-tutorial">Here’s a complete guide to WebSockets with React</a>.</p>
</li>
</ul>
<p>Technologies we’ll work with include:</p>
<ul>
<li><p><code>Go</code>, for building our backend system and enforcing real-time guarantees</p>
</li>
<li><p><code>React</code>, for building a responsive frontend <code>UI</code> that displays streamed events</p>
</li>
<li><p><code>Websocket</code>, for low-latency delivery of data from the backend to the client</p>
</li>
</ul>
<h2 id="heading-what-a-real-time-system-really-means">What a Real-Time System Really Means</h2>
<p>In a traditional web application, correctness is measured by whether the system produced the right result. In a real-time system, correctness is measured by whether the system produced the right result <strong>before the deadline</strong>. If the result from the test is “No”, then the system has failed – even though the result is correct.</p>
<h3 id="heading-types-of-real-time-systems">Types of Real-Time Systems</h3>
<p>There are a few different types of real-time systems that you should be aware of, each with varying levels of strictness:</p>
<table><tbody><tr><td><p><strong>Realtime System</strong></p></td><td><p><strong>Niche applicable&nbsp;</strong></p></td></tr><tr><td><p><strong>Hard Real-time: </strong>Missing a deadline is catastrophic here.</p></td><td><p>Flight Control &amp; Pacemakers</p></td></tr><tr><td><p><strong>Soft Real-time:</strong> Missing deadline degrades quality but does not crash the system.&nbsp;</p></td><td><p>Video Streaming &amp; Trading Dashboards</p></td></tr><tr><td><p><strong>Firm Real-time</strong>: Late results are useless and should be discarded.</p></td><td><p>Car Auction Web/Mobile Apps</p></td></tr></tbody></table>

<p>The majority of web-based real-time systems fall under the soft real-time category, and that’s exactly what we’ll build here.</p>
<h3 id="heading-why-most-web-apps-are-not-real-time">Why Most Web Apps Are Not Real-Time</h3>
<p>There are many reasons a system may not be real-time, and typically, even those marketed as real-time applications lack this guarantee.</p>
<p>Here’s why:</p>
<ol>
<li><p>Websockets guarantee delivery, not timeliness</p>
</li>
<li><p>Massage queues are optimized for durability and throughput </p>
</li>
<li><p>Infinite buffering hides deadlines </p>
</li>
<li><p>User Interfaces (UIs) render when they can, not when they should  </p>
</li>
</ol>
<p>In other words, data will arrive eventually, but nothing enforces when it must be processed. That’s exactly the gap we’ll address in this tutorial.</p>
<h2 id="heading-what-we-are-going-to-build">What We Are Going to Build</h2>
<p>In this tutorial, we’ll build a Deadline-Aware Live Event Monitor. You can think of it as a simplified real-time system for sensor data, trading events, alerts, or live telemetry.</p>
<p>Our app will have these features and constraints:</p>
<ul>
<li><p>Events are generated at a fixed rate</p>
</li>
<li><p>Each event has a deadline </p>
</li>
<li><p>The backend processes events only if they can be completed on time</p>
</li>
<li><p>Late events are marked or dropped </p>
</li>
<li><p>The frontend visualizes:</p>
<ul>
<li><p>processing latency </p>
</li>
<li><p>missed deadlines</p>
</li>
<li><p>and system health </p>
</li>
</ul>
</li>
</ul>
<p>This will give us the required metrics to measure the real-time behavior of the system instead of guessing.</p>
<h2 id="heading-system-architecture">System Architecture</h2>
<p>The high-level system architecture looks like this:</p>
<pre><code class="lang-plaintext">
+-------------+     +------------------+     +----------------+
| Event       | --&gt; | Deadline-Aware   | --&gt; | WebSocket      |
| Generator   |     | Go Processor     |     | Server         |
+-------------+     +------------------+     +----------------+
                                                     |
                                                     v
                                           +----------------+
                                           | React Dashboard|
                                           +----------------+
</code></pre>
<p>Let’s break down the responsibilities:</p>
<p><strong>Backend:</strong></p>
<ul>
<li><p>Generates time-sensitive events </p>
</li>
<li><p>Enforces deadline </p>
</li>
<li><p>Applies back pressure</p>
</li>
<li><p>Streams result to client (frontend)</p>
</li>
</ul>
<p><strong>Front End:</strong></p>
<ul>
<li><p>Consumes real-time events</p>
</li>
<li><p>Renders live metrics </p>
</li>
<li><p>Remains responsive under load </p>
</li>
</ul>
<h4 id="heading-time-is-part-of-your-data-model">Time is part of your Data Model</h4>
<p>In a real-time system, time is explicit, not implicit. This means that each event processed includes:</p>
<ul>
<li><p>when it was created </p>
</li>
<li><p>how long is it allowed to live, and</p>
</li>
<li><p>when it was processed </p>
</li>
</ul>
<p>Conceptually, a typical data model for an event looks like this:</p>
<pre><code class="lang-typescript">{
  id: <span class="hljs-built_in">string</span>
  createdAt: <span class="hljs-built_in">number</span>
  deadlineMs: <span class="hljs-built_in">number</span>
  processedAt?: <span class="hljs-built_in">number</span>
  status: <span class="hljs-string">"on-time"</span> | <span class="hljs-string">"late"</span> | <span class="hljs-string">"dropped"</span>
}
</code></pre>
<p>This is the mindset shift we hope to establish: in a real-time system, time is an essential component for your system that guarantees accuracy.</p>
<h2 id="heading-why-go-is-a-good-fit-for-our-use-case">Why Go is a Good Fit for Our Use Case</h2>
<p>Go is not a hard real-time language, but it’s excellent for soft real-time workloads. This is because of its:</p>
<ul>
<li><p>Cheap goroutines</p>
</li>
<li><p>Structured concurrency with channels</p>
</li>
<li><p>Deadline propagation via <code>context.Context</code></p>
</li>
<li><p>Simple runtime behavior</p>
</li>
</ul>
<p>Most importantly, Go makes it easy to <strong>fail fast</strong>, which is essential for real-time systems.</p>
<h3 id="heading-generating-events-with-go">Generating Events with Go</h3>
<p>We’ll begin the development of our backend system by first defining the Event struct and creating a fixed-rate event generator function:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Event <span class="hljs-keyword">struct</span> {
        ID         <span class="hljs-keyword">string</span>
        CreatedAt time.Time
        DeadlineMs  time.Duration
}
</code></pre>
<p>Here we’ve created an <code>Event</code> struct with the following properties:</p>
<ul>
<li><p><code>ID</code> a unique identifier that helps in the management of each event processed by the system</p>
</li>
<li><p><code>CreatedAt</code> to track the time the event was created</p>
</li>
<li><p><code>Deadline</code> to help evaluate if the event met the assigned deadline or if it failed</p>
</li>
</ul>
<p>Next, we’ll create the event generator <code>startGenerator</code> function:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">startGenerator</span><span class="hljs-params">(out <span class="hljs-keyword">chan</span>&lt;- Event)</span></span> {
        ticker := time.NewTicker(<span class="hljs-number">50</span> * time.Millisecond)
        <span class="hljs-keyword">defer</span> ticker.Stop()

        <span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> ticker.C {
                event := Event{
                        ID:         uuid.New().String(),
                        CreatedAt:  time.Now(),
                        DeadlineMs: <span class="hljs-number">100</span>,
                }


                <span class="hljs-keyword">select</span> {
                <span class="hljs-keyword">case</span> out &lt;- event:
                <span class="hljs-keyword">default</span>:
                  <span class="hljs-comment">// Drop event when load peaks on the goroutine</span>
                }
        }
}
</code></pre>
<p>Here, the event generator function accepts a <code>Go</code> channel as a parameter and uses a <code>time.Ticker</code> channel that fires every <strong>50 milliseconds</strong>. On each tick, it creates a new <code>Event</code> with a unique<code>ID</code>, a creation timestamp, and a <strong>deadline of 100 milliseconds</strong> (<code>DeadlineMs: 100</code>).</p>
<p>The generator then attempts to send the event into the output channel using a non-blocking send. If the channel is ready, the event is delivered immediately. If the channel is not ready (for example, because downstream consumers are slow or overloaded), the <code>default</code> case is executed, and the event is dropped.</p>
<p>Why do we have to drop the event here? Well, because hiding overload drops real-time guarantees. In short, <strong>dropping events is a deliberate backpressure strategy</strong>: it prevents overload from cascading through the system and protects latency bounds, which is often more important than completeness in real-time streaming systems.</p>
<h3 id="heading-deadline-aware-processing">Deadline-aware Processing</h3>
<p>Next, we’ll create the <code>processEvent</code> function to handle the processing of the event. In Go, you can enforce deadlines by using <code>context.WithTimeout</code> like this:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processEvent</span><span class="hljs-params">(event Event)</span> <span class="hljs-title">string</span></span> {
        ctx, cancel := context.WithTimeout(
                context.Background(),
                event.Deadline,
        )

        <span class="hljs-keyword">defer</span> cancel()
        workDone := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{})

        <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
                time.Sleep(<span class="hljs-number">50</span> * time.Millisecond)
                <span class="hljs-built_in">close</span>(workDone)

        }()

        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> &lt;-workDone:
                <span class="hljs-keyword">return</span> <span class="hljs-string">"on-time"</span>
        <span class="hljs-keyword">case</span> &lt;-ctx.Done():
                <span class="hljs-keyword">return</span> <span class="hljs-string">"late"</span>
        }
}
</code></pre>
<p>Here we’ve intentionally ensured that work finishes before the deadline or it fails immediately.</p>
<p>In the <code>processEvent</code> function, each event is processed under a hard deadline enforced by a context with a timeout. The timeout duration is derived directly from the event’s deadline, meaning the event is only considered valid within the specified time window.</p>
<p>The actual work is executed in a separate goroutine, which simulates processing by sleeping for <strong>50 milliseconds</strong> and then signaling completion by closing the <code>workDone</code> channel. We’ve intentionally structured this so that work either completes within the deadline or is treated as a failure immediately.</p>
<h3 id="heading-applying-back-pressure"><strong>Applying Back-Pressure</strong></h3>
<p>In real-time systems, queues do not solve overload – they merely postpone it. When incoming events arrive faster than they can be processed, a queue continues to grow, increasing the time each event spends waiting.</p>
<p>Buffers can also hide failure. By absorbing excess load, they create the illusion that the system is healthy, even as processing delays grow beyond acceptable limits. This hidden degradation is dangerous because the system continues operating in a compromised state, producing results that are technically correct but operationally useless due to lateness.</p>
<p>As queues and buffers grow, latency increases silently. There is often no explicit error or signal that deadlines are being missed – the system simply becomes slower over time. In real-time systems, this silent latency growth is especially harmful because it violates the assumption that results are delivered within a known and bounded time window.</p>
<p>For these reasons, I strongly recommend that you use bounded channels. When the system becomes overwhelmed, bounded channels enforce back-pressure by refusing additional work. Instead of blocking indefinitely or growing unbounded queues, the system drops events when it cannot keep up.</p>
<p>This behavior makes failures visible. Dropped events are an explicit signal that the system is operating beyond its capacity. Rather than degrading unpredictably, the system degrades in a controlled and observable way. In this context, dropping events is a feature, not a bug, because it preserves latency guarantees for the events that do get processed and allows operators to detect, reason about, and respond to overload conditions immediately.</p>
<h3 id="heading-streaming-events-to-the-browser">Streaming Events to the Browser</h3>
<p>Next, we’ll build the Websocket broadcast system to push processed events to the frontend using the <a target="_blank" href="http://github.com/gorilla/websocket">Gorilla</a> <code>Go</code> websocket package (but feel free to use any package of your choice).</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
        <span class="hljs-string">"encoding/json"</span>
        <span class="hljs-string">"net/http"</span>
        <span class="hljs-string">"github.com/gorilla/websocket"</span>
)

<span class="hljs-keyword">var</span> upgrader = websocket.Upgrader{
        CheckOrigin: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(r *http.Request)</span> <span class="hljs-title">bool</span></span> {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
        },
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">wsHandler</span><span class="hljs-params">(out &lt;-<span class="hljs-keyword">chan</span> Event)</span> <span class="hljs-title">http</span>.<span class="hljs-title">HandlerFunc</span></span> {
        <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
                conn, _ := upgrader.Upgrade(w, r, <span class="hljs-literal">nil</span>)
                <span class="hljs-keyword">defer</span> conn.Close()
                <span class="hljs-keyword">for</span> event := <span class="hljs-keyword">range</span> out {
                        data, _ := json.Marshal(event)
                        conn.WriteMessage(websocket.TextMessage, data)
                }
        }
}
</code></pre>
<p>Here, we simply upgrade an incoming <code>HTTP</code> request to a <code>WebSocket</code> connection and continuously reads events from our <code>Event</code> channel we created earlier, serializing each event to <code>JSON</code> and broadcasting it to the connected client. It acts purely as a transport layer, pushing already-processed events to clients with low latency.  </p>
<p>It’s important to note that <code>WebSockets</code> do not make a system real-time. <code>WebSockets</code> merely provide low-latency delivery from the backend to the client. The real-time guarantees are established earlier in the backend pipeline through deliberate design choices: fixed-rate event generation, explicit per-event deadlines, bounded queues, non-blocking sends, deadline-aware processing using contexts, and fail-fast behavior when deadlines are exceeded.</p>
<p>By the time an event is sent over a <code>WebSocket</code>, it has already either met its real-time constraints or been discarded. The <code>WebSocket</code> layer simply transports the result – it doesn’t enforce or create real-time behavior.</p>
<h3 id="heading-consuming-a-websocket-event-react-typescript">Consuming a WebSocket Event (React + TypeScript)</h3>
<p>Up until now, we’ve been building the backend of our real-time event generator and broadcast system. In the next sections, we’ll build the frontend of the system using <code>React</code> and <code>TypeScript</code>.</p>
<p>We’ll start by initializing a <code>WebSocket</code> client to consume incoming events from the backend using the traditional WebSocket browser interface.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">"ws://localhost:8080/ws"</span>);
socket.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(event.data);
  buffer.push(data);
};
</code></pre>
<p>Here we simply initialize a new <code>WebSocket</code>, passing along the WebSocket URL from the backend. You have to reference the same URL. Instead of rendering every message immediately, it’s recommended that you always batch updates.</p>
<h3 id="heading-making-react-real-time-friendly">Making React Real-Time Friendly</h3>
<p>Next, let’s create a <code>React</code> <code>useRealTimeEvents</code> hook to handle streaming and processing of event broadcasts from the backend. Rendering on every message causes render storms, UI lag, and misleading dashboards. Instead, we render on animation frames.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { RealTimeEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'types/types'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useRealTimeEvents</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [events, setEvents] = useState&lt;RealTimeEvent[]&gt;([]);
  <span class="hljs-keyword">const</span> buffer = useRef&lt;RealTimeEvent[]&gt;([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> ws = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">'ws://localhost:8080/ws'</span>);
    ws.onmessage = <span class="hljs-function">(<span class="hljs-params">msg</span>) =&gt;</span> {
      buffer.current.push(<span class="hljs-built_in">JSON</span>.parse(msg.data));
    };

    <span class="hljs-keyword">let</span> raf: <span class="hljs-built_in">number</span>;

    <span class="hljs-keyword">const</span> flush = <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">if</span> (buffer.current.length &gt; <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">const</span> pendingEvents = buffer.current.slice(<span class="hljs-number">0</span>);

        setEvents(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> next = [...prev, ...pendingEvents];
          <span class="hljs-keyword">return</span> next.slice(<span class="hljs-number">-50</span>);
        });
      }
      raf = requestAnimationFrame(flush);
    };

    raf = requestAnimationFrame(flush);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      ws.close();
      cancelAnimationFrame(raf);
    };
  }, []);
  <span class="hljs-keyword">return</span> events;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> useRealTimeEvents;
</code></pre>
<p>The UI is part of the real-time system. It’s important to note that the system broadcasts messages to the frontend in milliseconds. This behavior already crosses the web browser refresh rate threshold.</p>
<p>In certain situations, you might even guess that the use of <code>setTime</code> should come in handy here. And that’s a good alternative – but there’s a better solution: using <code>requestAnimationFrame()</code>.</p>
<p>The <code>requestAnimationFrame()</code> takes in a callback function <code>flush</code> which is regulated by the animation frame, ensuring that we don’t cross the refresh rate threshold before the next repaint. You can learn more about it <code>requestAnimationFrame()</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope/requestAnimationFrame">here</a>.</p>
<h3 id="heading-creating-the-statsbar-component">Creating the StatsBar Component</h3>
<p>Next, let’s create a little <code>statusBar</code> component to show events that arrived within the deadline and those that came in late.</p>
<p>Create a new component <code>StatsBar</code> and add the code below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { <span class="hljs-keyword">type</span> FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { RealTimeEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'types/types'</span>;

<span class="hljs-keyword">const</span> StatsBar: FC&lt;{ events: RealTimeEvent[] }&gt; = <span class="hljs-function">(<span class="hljs-params">{ events }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> late = events.filter(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e.status === <span class="hljs-string">'late'</span>).length;
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"flex flex-row gap-2 bg-gray-500 w-full py-2.5 px-2"</span>&gt;
      &lt;strong&gt;Events: {events.length} | &lt;/strong&gt;
      &lt;strong&gt;Late: {late}&lt;/strong&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> StatsBar;
</code></pre>
<p>Here we are creating a minimal stats component to show the total number of events and those that arrived late by looping through the incoming event list whose statuses are late.</p>
<h3 id="heading-creating-the-events-table">Creating the Events Table</h3>
<p>Next, we’ll create a <code>EventTable</code> component to display the events.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { <span class="hljs-keyword">type</span> FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { RealTimeEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'types/types'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> EventsTable: FC&lt;{ events: RealTimeEvent[] }&gt; = <span class="hljs-function">(<span class="hljs-params">{ events }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> formatDate = <span class="hljs-function">(<span class="hljs-params">date: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date).toLocaleString();
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"w-full"</span>&gt;
      &lt;div className=<span class="hljs-string">"relative overflow-x-auto bg-neutral-primary-soft shadow-xs rounded-base border border-default"</span>&gt;
        &lt;table className=<span class="hljs-string">"w-full text-sm text-left rtl:text-right text-body"</span>&gt;
          &lt;thead className=<span class="hljs-string">"text-sm text-body bg-neutral-secondary-soft border-b rounded-base border-default"</span>&gt;
            &lt;tr&gt;
              &lt;th scope=<span class="hljs-string">"col"</span> className=<span class="hljs-string">"px-6 py-3 font-medium"</span>&gt;
                ID
              &lt;/th&gt;
              &lt;th scope=<span class="hljs-string">"col"</span> className=<span class="hljs-string">"px-6 py-3 font-medium"</span>&gt;
                Satus
              &lt;/th&gt;
              &lt;th scope=<span class="hljs-string">"col"</span> className=<span class="hljs-string">"px-6 py-3 font-medium"</span>&gt;
                Created At
              &lt;/th&gt;
              &lt;th scope=<span class="hljs-string">"col"</span> className=<span class="hljs-string">"px-6 py-3 font-medium"</span>&gt;
                Processed At
              &lt;/th&gt;
              &lt;th scope=<span class="hljs-string">"col"</span> className=<span class="hljs-string">"px-6 py-3 font-medium"</span>&gt;
                Deadline
              &lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            {events.map(<span class="hljs-function">(<span class="hljs-params">e, i</span>) =&gt;</span> (
              &lt;tr
                key={e.id + i}
                className=<span class="hljs-string">"bg-neutral-primary border-b border-default"</span>
              &gt;
                &lt;td className=<span class="hljs-string">"px-6 py-4"</span>&gt;{e.id.slice(<span class="hljs-number">0</span>, <span class="hljs-number">6</span>)}&lt;/td&gt;
                &lt;td className=<span class="hljs-string">"px-6 py-4"</span>&gt;{e.status}&lt;/td&gt;
                &lt;td className=<span class="hljs-string">"px-6 py-4"</span>&gt;{formatDate(e.createdAt)}&lt;/td&gt;
                &lt;td className=<span class="hljs-string">"px-6 py-4"</span>&gt;{formatDate(e.processedAt)}&lt;/td&gt;
                &lt;td className=<span class="hljs-string">"px-6 py-4"</span>&gt;{e.deadlineMs}&lt;/td&gt;
              &lt;/tr&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>Here we loop through all incoming events and display the event’s <code>id</code>, <code>status</code>, and <code>deadline</code>. These metrics will help us gain insight into the performance of our real-time events broadcast system.</p>
<h3 id="heading-putting-it-all-together">Putting it All Together</h3>
<p>At this point, we have implemented a complete, end-to-end real-time application that connects a deadline-aware <code>Go</code> backend to a lightweight <code>React</code> frontend. On the backend, events are generated at a fixed rate, processed under explicit deadlines, and dropped when the system is under load to preserve real-time guarantees. Only events that meet these guarantees are forwarded to connected clients via <code>WebSocket</code> broadcast.</p>
<p>On the frontend, we’ve built the <code>useRealtimeEvents</code> hook to establish a persistent <code>WebSocket</code> connection and continuously stream events from the backend as they arrive. The <code>StatsBar</code> component provides immediate visibility into the system’s behavior by summarizing key characteristics of the event stream, while the <code>EventTable</code> component renders individual events in the order they are received. Together, these components clearly mirror the behavior of the system under normal conditions in real-time.</p>
<p>With both the frontend and backend components in place, the application now functions as a real-time monitor. The backend enforces timelines and correctness, and the frontend simply reflects the outcome of those decisions in real-time. There is no buffering or replay logic on the client side – what’s displayed on the <code>UI</code> is exactly what the system was able to process within the specified deadline.</p>
<p>Finally, replace your <code>Welcome</code> component with the code below to display the <code>StatusBar</code> and <code>EventsTable</code> component.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useRealtimeEvents } <span class="hljs-keyword">from</span> <span class="hljs-string">"./hooks/useRealtimeEvents"</span>;
<span class="hljs-keyword">import</span> { StatsBar } <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/StatsBar"</span>;
<span class="hljs-keyword">import</span> { EventTable } <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/EventTable"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> events = useRealtimeEvents();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Real-Time Event Monitor&lt;/h1&gt;
      &lt;StatsBar events={events} /&gt;
      &lt;EventTable events={events} /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>The React frontend is scaffolded using <a target="_blank" href="https://react.dev/learn/creating-a-react-app">create-react-app</a>, but the same approach can be used for other frameworks, such as <code>Next.js</code> or <code>Vite</code>. The complete source code, including the frontend and backend, is available in the repository <a target="_blank" href="https://github.com/emmanueletukudo/realtime-go-react">here</a>. You can reach out to me on the <a target="_blank" href="https://x.com/eetukudo_">X platform</a> if you need my assistance.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>If you’ve followed this tutorial up to this point, congratulations! You’ve learnt the most critical part of building resilient deadline-aware real-time systems.</p>
<p>Remember, real-time systems are not about being fast, but about how <strong>predictable they are.</strong> You don’t need a Real-Time Operating System (RTOS), a PhD, or specialized hardware to start learning real-time design.</p>
<p>All you need to excel is to respect time, bound your resources, and accept that sometimes, dropping data is the correct behavior. If you understand that, you’re already thinking like a real-time systems engineer.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Server-Sent Events vs WebSockets – How to Choose a Real-Time Data Exchange Protocol ]]>
                </title>
                <description>
                    <![CDATA[ In our fast-paced digital era, real-time data exchange has become critical in creating responsive and dynamic user experiences. It’s especially important in applications like live news updates, chat systems, AI generative platforms, and so on. In thi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/server-sent-events-vs-websockets/</link>
                <guid isPermaLink="false">677835cd5280589b2bc82110</guid>
                
                    <category>
                        <![CDATA[ development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Svitlana Lorman ]]>
                </dc:creator>
                <pubDate>Fri, 03 Jan 2025 19:09:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734440242816/4ba6ef33-386a-45f7-872b-5974742855e2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In our fast-paced digital era, real-time data exchange has become critical in creating responsive and dynamic user experiences. It’s especially important in applications like live news updates, chat systems, AI generative platforms, and so on.</p>
<p>In this article, you’ll learn about <strong>WebSockets</strong> and <strong>Server-Sent Events (SSE)</strong>, two powerful communication protocols that ensure seamless, real-time interactions in modern web applications.</p>
<p>By examining their differences, advantages, and use cases, you’ll gain a clear understanding of how to choose the right protocol to optimize scalability and performance. This article also includes simple example implementations using <strong>Node.js</strong>, allowing you to see these technologies in action.</p>
<p>To help you solidify your knowledge further, we’ll conclude with practical project recommendations, offering hands-on opportunities to apply what you’ve learned.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-websocket">What is a WebSocket?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advantages-of-websockets">Advantages and Disadvantages of WebSockets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-websockets">Use Cases for WebSockets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-websocket-server-with-nodejs">How to Create a WebSocket Server with Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-server-sent-events-sse">What are Server-Sent Events (SSE)?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advantages-of-server-sent-events">Advantages and Disadvantages of Server-Sent Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-sse">Use Cases for SSE</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-server-sent-events-using-node-js">How to Implement Server-Sent Events using Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-websockets-vs-server-sent-events">WebSockets vs Server-Sent Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-which-is-better-server-sent-events-or-websockets">Which is Better: Server-Sent Events or WebSockets?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-websocket"><strong>What is a WebSocket?</strong></h2>
<p>In short, a WebSocket is a communication protocol that enables full-duplex, low-latency, event-driven connections between the server and the browser. In case you’re not familiar, full-duplex refers to the ability to send and receive data simultaneously between a client (like a web browser) and a server over a single connection.</p>
<p>Unlike <a target="_blank" href="https://www.freecodecamp.org/news/what-is-http/">HTTP</a>, which operates in a request-response model, WebSockets enable persistent and continuous data exchange. This means that the data is exchanged in real-time, and pulling it from the server is unnecessary each time.</p>
<p>The WebSockets protocol was formalized in 2011 by the IETF through RFC 6455 and is now supported by all major browsers (Chrome, Edge, Safari, and so on).</p>
<p>Although WebSockets differ from HTTP, both protocols operate on the <a target="_blank" href="https://www.freecodecamp.org/news/osi-model-networking-layers-explained-in-plain-english/">OSI model’</a>s Application Layer (layer 7) and rely on <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tcp-ip-layers-and-protocols-explained/">TCP/IP</a> at the Transport Layer (layer 4). The OSI (Open Systems Interconnection) model is a conceptual framework used to understand network communication. It divides the network into 7 layers, each responsible for a specific function, from physical data transmission to application-level interactions.</p>
<p>Similar to HTTP and HTTPS<em>,</em> WebSockets have a unique set of prefixes:</p>
<ul>
<li><p><strong>ws</strong>: indicates an unencrypted connection without TLS and should not be opened from HTTPS-secured sites.</p>
</li>
<li><p><strong>wss</strong>: indicates an encrypted connection secured by TLS and shouldn’t be opened from HTTP (non-secure) sites.</p>
</li>
</ul>
<h3 id="heading-how-do-websockets-work"><strong>How Do WebSockets Work?</strong></h3>
<p>As I mentioned earlier, WebSockets establish a persistent, bidirectional connection between the client and the server. The process begins with an HTTP handshake initiated by the client, where the client requests a WebSocket connection by sending a specific header to the server. If the server accepts the request, it responds with a status code 101 confirming the upgrade to a WebSocket connection.</p>
<p>Once the connection is established, the WebSocket protocol takes over, and both the client and the server can send and receive data at any time without the need for repeated handshakes. This continuous connection allows real-time communication with minimal latency, as data is exchanged immediately without waiting for additional requests.</p>
<p>The WebSocket connection remains open until either the client or server decides to close it. This ensures efficient and fast data exchange, making it ideal for real-time applications like chat systems, online gaming, or live data feeds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735898910124/24538662-d00f-4457-a8a4-9da16f618046.png" alt="WebSocket full-duplex client-server connection " class="image--center mx-auto" width="1600" height="900" loading="lazy"></p>
<h3 id="heading-advantages-of-websockets"><strong>Advantages of WebSockets</strong></h3>
<ul>
<li><p><strong>Full-duplex connection</strong>: both client and server can send and receive data simultaneously.</p>
</li>
<li><p><strong>Low latency:</strong> since WebSockets maintain an open connection, they ensure minimal delay in data transfer by eliminating the overhead of repeatedly establishing and tearing down connections, ensuring minimal delay in data transfer.</p>
</li>
<li><p><strong>Reduced bandwidth usage:</strong> unlike HTTP requests, which include headers for every request, WebSockets only require a single handshake, resulting in smaller data packets and reduced bandwidth consumption.</p>
</li>
<li><p><strong>Cross-Platform Compatibility:</strong> as stated earlier, WebSockets are supported by most modern browsers and programming frameworks, which ensures broad applicability.</p>
</li>
</ul>
<h3 id="heading-disadvantages-of-websockets"><strong>Disadvantages of WebSockets</strong></h3>
<ul>
<li><p><strong>Complexity in implementation</strong>: WebSockets require a dedicated server and a special protocol.</p>
</li>
<li><p><strong>Vulnerability to attacks</strong>: Without proper security (wss prefix) and authentication mechanisms, WebSockets are susceptible to <a target="_blank" href="https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking">cross-site WebSocket hijacking</a> (CSWSH) and <a target="_blank" href="https://www.ibm.com/think/topics/man-in-the-middle">man-in-the-middle (MITM)</a> attacks.</p>
</li>
<li><p><strong>No built-in security</strong>: Unlike HTTP, WebSockets do not inherently support request-response headers for additional security. Thus, it’s necessary to implement token-based authentication or other secure methods manually.</p>
</li>
</ul>
<h2 id="heading-use-cases-for-websockets"><strong>Use Cases for WebSockets</strong></h2>
<p>WebSockets have revolutionized how applications deliver real-time communication. This protocol powers various industries by enabling low-latency, bidirectional data flow. Let’s talk about some good use cases for WebSockets:</p>
<h3 id="heading-1-chat-applications">1. Chat Applications</h3>
<p>WebSockets’ full-duplex connection ensures that messages are delivered instantly and without interruptions, making them the perfect choice for real-time communication. This technology powers platforms like Slack, Discord, and various live customer support chat systems, providing seamless and efficient interactions.</p>
<h3 id="heading-2-online-gaming">2. Online Gaming</h3>
<p>WebSockets are essential for fast-paced online games like Clash Royal, where real-time communication between players and servers is crucial. By maintaining a persistent, two-way connection, WebSockets allow immediate transmission of actions, such as moves or attacks, ensuring that all players experience seamless gameplay without lag. </p>
<h3 id="heading-3-real-time-dashboards">3. Real-Time Dashboards</h3>
<p>Tools like Datadog and e-commerce platforms use WebSockets to ensure system metrics, sales, and inventory data are always current, eliminating manual refreshes and enhancing user experience.</p>
<p>WebSockets also excel at handling big data, streaming, and visualizing large volumes of information with low latency. This makes them the perfect choice for industries such as finance, healthcare, and logistics, where real-time insights are essential for effective decision-making. </p>
<p>An example is DataTableDev, a grid prototype capable of working with massive data volumes, demonstrating WebSockets’ potential in real-time data processing.</p>
<h2 id="heading-how-to-create-a-websocket-server-with-nodejs"><strong>How to Create a WebSocket Server with Node.js</strong></h2>
<p>Before setting up a simple WebSocket server with Node.js to handle secure connections, you’ll need a <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tls-transport-layer-security-encryption-explained-in-plain-english/">TLS certificate</a> to ensure the communication is encrypted. You can acquire one from a trusted Certificate Authority (CA) like <a target="_blank" href="https://letsencrypt.org/">Let's Encrypt</a> or use a self-signed certificate for testing.</p>
<p>Below is the complete implementation of a WebSocket Secure (WSS) server using Node.js:</p>
<p>We’ll start on the server-side. Firstly, let’s import the required modules:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> https = <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>);  <span class="hljs-comment">// Module for creating an HTTPS server</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);        <span class="hljs-comment">// Module to read files (used to load TLS certificates)</span>
<span class="hljs-keyword">const</span> WebSocket = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ws'</span>); <span class="hljs-comment">// WebSocket library to handle WebSocket connections</span>
</code></pre>
<p>Next, we’ll load TLS certificates for secure communication (wss://).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> serverOptions = {
  <span class="hljs-attr">cert</span>: fs.readFileSync(<span class="hljs-string">'cert.pem'</span>), <span class="hljs-comment">// Load the TLS certificate for HTTPS encryption</span>
  <span class="hljs-attr">key</span>: fs.readFileSync(<span class="hljs-string">'key.pem'</span>),   <span class="hljs-comment">// Load the private key associated with the certificate</span>
};
</code></pre>
<p><code>serverOptions</code> reads the TLS certificate and private key from files (<code>cert.pem</code> and <code>key.pem</code>) and holds them. These are essential for establishing secure communication using the <code>wss://</code> protocol since they enable <strong>encryption</strong> for data transmitted between the server and the client.</p>
<p>Since the WebSocket server runs on top of the HTTPS server, we first create and initialize the HTTPS server using the <code>serverOptions</code>, and then set up the WebSocket server.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create the HTTPS server with the loaded certificates and initialize it with TLS options</span>
<span class="hljs-keyword">const</span> httpsServer = https.createServer(serverOptions); 
<span class="hljs-comment">// Create a WebSocket server that runs on top of the HTTPS server</span>
<span class="hljs-keyword">const</span> wss = <span class="hljs-keyword">new</span> WebSocket.Server({ <span class="hljs-attr">server</span>: httpsServer });
</code></pre>
<p>Now it's time to define the behavior when a new WebSocket connection is established. You'll need to handle incoming messages from the WebSocket client, send a response back, and manage the disconnection process. In this tutorial, we'll keep it simple by printing the received data to the console.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the behavior when a new WebSocket connection is established</span>
wss.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">ws</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client connected'</span>);

  <span class="hljs-comment">// Handle incoming messages from the WebSocket client</span>
  ws.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Received: <span class="hljs-subst">${message}</span>`</span>); 
    ws.send(<span class="hljs-string">`Server received: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Send a response back to the client</span>
  });

  <span class="hljs-comment">// Handle when a client disconnects</span>
  ws.on(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client disconnected'</span>);

  <span class="hljs-comment">// Send an initial message to the client when the connection is established</span>
  ws.send(<span class="hljs-string">'Welcome to the secure WebSocket server!'</span>);
});
</code></pre>
<p>Last but not least, you need to define the port where the HTTPS WebSocket server will listen for incoming connections. In this example, we use a port <code>8080</code>. After that, we start the HTTPS server and make it listen on the specified port. Once the server is up and running a log message will be printed to confirm that the secure WebSocket server is ready.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the port where the HTTPS WebSocket server will listen for incoming connections</span>
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">8080</span>;

<span class="hljs-comment">// Start the HTTPS server and begin listening on the specified port</span>
httpsServer.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Secure WebSocket server running at wss://localhost:<span class="hljs-subst">${PORT}</span>`</span>); <span class="hljs-comment">// Log a message when the server starts</span>
});
</code></pre>
<p>And that’s it for the server-side part. Your full code should look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import required modules</span>
<span class="hljs-keyword">const</span> https = <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>);  <span class="hljs-comment">// Module for creating an HTTPS server</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);        <span class="hljs-comment">// Module to read files (used to load TLS certificates)</span>
<span class="hljs-keyword">const</span> WebSocket = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ws'</span>); <span class="hljs-comment">// WebSocket library to handle WebSocket connections</span>

<span class="hljs-comment">// Load TLS certificates for secure communication (wss://)</span>
<span class="hljs-keyword">const</span> serverOptions = {
  <span class="hljs-attr">cert</span>: fs.readFileSync(<span class="hljs-string">'cert.pem'</span>), <span class="hljs-comment">// Load the TLS certificate for HTTPS encryption</span>
  <span class="hljs-attr">key</span>: fs.readFileSync(<span class="hljs-string">'key.pem'</span>),   <span class="hljs-comment">// Load the private key associated with the certificate</span>
};

<span class="hljs-comment">// Create the HTTPS server with the loaded certificates and initialize it with TLS options</span>
<span class="hljs-keyword">const</span> httpsServer = https.createServer(serverOptions); 
<span class="hljs-comment">// Create a WebSocket server that runs on top of the HTTPS server</span>
<span class="hljs-keyword">const</span> wss = <span class="hljs-keyword">new</span> WebSocket.Server({ <span class="hljs-attr">server</span>: httpsServer }); 

<span class="hljs-comment">// Define the behavior when a new WebSocket connection is established</span>
wss.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">ws</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client connected'</span>); 

  <span class="hljs-comment">// Handle incoming messages from the WebSocket client</span>
  ws.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Received: <span class="hljs-subst">${message}</span>`</span>); 
    ws.send(<span class="hljs-string">`Server received: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Send a response back to the client</span>
  });

  <span class="hljs-comment">// Handle when a client disconnects</span>
  ws.on(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client disconnected'</span>); 
  });
  <span class="hljs-comment">// Send an initial message to the client when the connection is established</span>
  ws.send(<span class="hljs-string">'Welcome to the secure WebSocket server!'</span>);
});

<span class="hljs-comment">// Define the port where the HTTPS WebSocket server will listen for incoming connections</span>
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">8080</span>;

<span class="hljs-comment">// Start the HTTPS server and begin listening on the specified port</span>
httpsServer.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Secure WebSocket server running at wss://localhost:<span class="hljs-subst">${PORT}</span>`</span>); <span class="hljs-comment">// Log a message when the server starts</span>
});
</code></pre>
<p>To run the created server with Node.js, type the following line into Command Prompt / Terminal:</p>
<p> <code>node wss-server.js</code></p>
<p>Connect to the server using a WebSocket client or browser console at <code>wss://</code><a target="_blank" href="http://localhost:8080"><code>localhost:8080</code></a>.</p>
<p>Once the connection is established, the client can send and receive messages. Now well look at a simple example of how to receive and send messages on the client side.</p>
<p>To start, let’s define a basic HTML structure:</p>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;title&gt;WebSocket Client&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;WebSocket Client&lt;/h1&gt;
  &lt;div id="messages"&gt;&lt;/div&gt;
  &lt;input type="text" id="messageInput" placeholder="Type a message"&gt;
  &lt;button onclick="sendMessage()"&gt;Send Message&lt;/button&gt;

  &lt;script&gt;
    &lt;!-- JS code goes here --&gt;
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>The <code>&lt;button&gt;</code> element has an <code>onclick</code> event that triggers the <code>sendMessage()</code> function when clicked. Before we dive into the function, let's first establish a WebSocket connection to the server. We'll also define event listeners to handle the following:</p>
<ol>
<li><p>When the WebSocket connection is successfully established.</p>
</li>
<li><p>When a message is received from the server.</p>
</li>
</ol>
<p>These event listeners will ensure that we can interact with the server and handle incoming data in real time.</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Establish a WebSocket connection to the server</span>
    <span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">'wss://localhost:8080'</span>); 

    <span class="hljs-comment">// Event listener for when the WebSocket connection is established</span>
    socket.addEventListener(<span class="hljs-string">'open'</span>, <span class="hljs-function">() =&gt;</span> {
      displayMessage(<span class="hljs-string">'Connected to the WebSocket server'</span>);

    <span class="hljs-comment">// Event listener for when a message is received from the server</span>
    socket.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      displayMessage(<span class="hljs-string">`Server: <span class="hljs-subst">${event.data}</span>`</span>); <span class="hljs-comment">// Display the message received from the server</span>
    });
</code></pre>
<p>To display the message on the user interface, we've created a function called <code>displayMessage</code>. Here's how it's defined:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Function to display messages in the message container</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayMessage</span>(<span class="hljs-params">message</span>) </span>{
      <span class="hljs-keyword">const</span> messageDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>); <span class="hljs-comment">// Get the div where messages will be displayed</span>
      <span class="hljs-keyword">const</span> newMessage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>); <span class="hljs-comment">// Create a new paragraph element for the new message</span>
      newMessage.textContent = message; <span class="hljs-comment">// Set the text content of the paragraph to the message</span>
      messageDiv.appendChild(newMessage); <span class="hljs-comment">// Add the new paragraph to the message container</span>
}
</code></pre>
<p>Now, it’s time to define the <code>sendMessage()</code> function. Firstly, we retrieve a message and then send it to the WebSocket server using the <code>socket.send()</code> method. This transmits the message over the WebSocket connection established earlier, allowing the server to receive it. Next, on the UI, we display the message and clear the input field.</p>
<p>Thus, the code looks the following way:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Function to send a message to the server</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> message = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value; <span class="hljs-comment">// Get the message from the input field</span>
      socket.send(message); <span class="hljs-comment">// Send the message over the WebSocket connection</span>
      displayMessage(<span class="hljs-string">`You: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Display the message in the UI as sent by the user</span>
      <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the input field after sending the message</span>
    }
</code></pre>
<p>The final step is to set the event listener for when the WebSocket connection closes. To keep it simple, we will log a message to the console.</p>
<pre><code class="lang-javascript"> socket.addEventListener(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Disconnected from the WebSocket server'</span>); 
 });
</code></pre>
<p>This is what the client-side part looks like:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>WebSocket Client<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>WebSocket Client<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"messages"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"messageInput"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type a message"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"sendMessage()"</span>&gt;</span>Send Message<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-comment">// Establish a WebSocket connection to the server</span>
    <span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">'wss://localhost:8080'</span>); <span class="hljs-comment">// Connect to WebSocket server </span>

    <span class="hljs-comment">// Event listener for when the WebSocket connection is established</span>
    socket.addEventListener(<span class="hljs-string">'open'</span>, <span class="hljs-function">() =&gt;</span> {
      displayMessage(<span class="hljs-string">'Connected to the WebSocket server'</span>);

    <span class="hljs-comment">// Event listener for when a message is received from the server</span>
    socket.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      displayMessage(<span class="hljs-string">`Server: <span class="hljs-subst">${event.data}</span>`</span>); <span class="hljs-comment">// Display the message received from the server</span>
    });

    <span class="hljs-comment">// Function to send a message to the server</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> message = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value; <span class="hljs-comment">// Get the message from the input field</span>
      socket.send(message); <span class="hljs-comment">// Send the message over the WebSocket connection</span>
      displayMessage(<span class="hljs-string">`You: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Display the message in the UI as sent by the user</span>
      <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the input field after sending the message</span>
    }

    <span class="hljs-comment">// Function to display messages in the message container</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayMessage</span>(<span class="hljs-params">message</span>) </span>{
      <span class="hljs-keyword">const</span> messageDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>); <span class="hljs-comment">// Get the div where messages will be displayed</span>
      <span class="hljs-keyword">const</span> newMessage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>); <span class="hljs-comment">// Create a new paragraph element for the new message</span>
      newMessage.textContent = message; <span class="hljs-comment">// Set the text content of the paragraph to the message</span>
      messageDiv.appendChild(newMessage); <span class="hljs-comment">// Add the new paragraph to the message container</span>
    }

    <span class="hljs-comment">// Event listener for when the WebSocket connection is closed</span>
    socket.addEventListener(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Disconnected from the WebSocket server'</span>); 
    });
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h2 id="heading-what-are-server-sent-events-sse"><strong>What are Server-Sent Events (SSE)?</strong></h2>
<p>Server-Sent Events (SSE) is a technology that enables a web server to push updates to a web page. As part of the HTML5 specification, it functions similarly to WebSockets by using a single, long-lived HTTP connection to deliver data in real-time.</p>
<p>The concept of SSE originated in 2004, with the <a target="_blank" href="https://blogs.opera.com/news/">Opera team</a> taking the first steps towards implementation in 2006. One of the main limitations of SSE in the early stages was the connection cap imposed by HTTP/1.1, which restricted the number of simultaneous connections a client could establish with a server. But with the introduction of HTTP/2, this limitation was removed. HTTP/2 allows multiple data streams to flow over a single connection through multiplexing, enabling more efficient and scalable communication for SSE.</p>
<p>Server-sent events (SSE) rely on two fundamental components:</p>
<ul>
<li><strong>EventSource</strong>: An interface defined by the WHATWG specification and implemented by modern browsers. It enables the client (typically a browser) to subscribe to server-sent events.  </li>
</ul>
<ul>
<li><strong>EventStream</strong>: A protocol that specifies the plain-text format servers must use to send events, ensuring compatibility with the EventSource client for seamless communication.  </li>
</ul>
<p>As the specification outlines, events can include arbitrary text data and an optional ID and are separated by newlines. Also, SSE events have a dedicated <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/MIME_types">MIME type</a>: <code>text/event-stream.</code> A MIME type (Multipurpose Internet Mail Extensions type) is a standard that indicates the nature and format of a file or data, allowing the browser or server to properly interpret and handle it.</p>
<h3 id="heading-how-do-server-sent-events-work"><strong>How do Server-Sent Events Work?</strong></h3>
<p>Server-sent events (SSE) work by establishing a persistent, one-way communication channel from the server to the client over a standard HTTP connection. The client initiates the connection by creating an <code>EventSource</code> object, which sends a request to the server to start streaming data. Once the server receives this request, it responds by sending a continuous stream of updates in a specific <code>text/event-stream</code> format. The client listens for these events, automatically handling any reconnections if the connection is lost.</p>
<p>SSE is ideal for applications that require real-time updates from the server, such as live news feeds or notifications, as it ensures a constant flow of information with minimal overhead.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735897258671/eec0599a-f5b5-43f2-8552-7f84ac265c3e.png" alt="This picture outlines how SSE works" class="image--center mx-auto" width="1600" height="900" loading="lazy"></p>
<h3 id="heading-advantages-of-server-sent-events"><strong>Advantages of Server-Sent Events</strong></h3>
<ul>
<li><p><strong>Polyfill capability</strong>: Server-sent events (SSE) can be implemented using JavaScript in browsers that don’t natively support them. This ensures backward compatibility by leveraging the standard SSE interface instead of creating a custom alternative.  </p>
</li>
<li><p><strong>Automatic reconnection</strong>: SSE connections are designed to reconnect automatically after interruption. Thus, they reduce the need for extra code to handle this essential functionality.  </p>
</li>
<li><p><strong>Firewall-friendly</strong>: SSEs work seamlessly with corporate firewalls that perform packet inspection, making them a reliable choice for enterprise applications.</p>
</li>
</ul>
<h3 id="heading-disadvantages-of-server-sent-events"><strong>Disadvantages of Server-Sent Events</strong></h3>
<ul>
<li><p><strong>Data format restrictions</strong>: SSE is restricted to transmitting messages in UTF-8 format, as it does not support binary data.  </p>
</li>
<li><p><strong>Connection limits</strong>: Browsers cap the number of simultaneous SSE connections to six per client. This limitation becomes problematic when multiple tabs require active SSE connections. For more details and potential workarounds, refer to this StackOverflow thread: <a target="_blank" href="https://stackoverflow.com/questions/18584525/server-sent-events-and-browser-limits">Server-Sent Events and browser limits</a>.</p>
</li>
<li><p><strong>One-way communication</strong>: SSE supports only server-to-client messaging, making it ideal for read-only real-time applications like stock tickers. However, this unidirectional nature can be a constraint for more interactive real-time applications.</p>
</li>
</ul>
<h2 id="heading-use-cases-for-sse"><strong>Use Cases for SSE</strong></h2>
<p>Server-sent events are widely used in applications where real-time data delivery is crucial. SSE enables the server to push updates to the client automatically, making it ideal for applications that require live information streams. From news feeds to financial dashboards, SSE ensures that users receive the latest content without constant page refreshes.</p>
<p>Here are some common use cases for using SSE:</p>
<h3 id="heading-1-social-media-feeds">1. Social Media Feeds</h3>
<p>Social media platforms leverage SSE to push new posts instantly, likes, and comments to users’ feeds, providing a more dynamic and engaging user experience. A great example is Twitter’s (X’s) real-time feed implementation, which allows them to push real-time updates to the browser.</p>
<h3 id="heading-2-enterprise-monitoring-system">2. Enterprise Monitoring System</h3>
<p>SSE enables financial monitoring systems and other real-time applications to deliver live data updates efficiently. For instance, Netflix’s open-source Hystrix, a well-known component for microservice monitoring and circuit breaking, includes a web dashboard that displays real-time performance metrics and circuit status. This dashboard uses SSE to push performance data in real-time, ensuring that users can monitor the health and performance of microservices as they happen. The dashboard leveraging SSE provides an efficient, low-latency solution for updating performance data without needing constant manual refreshing or polling.</p>
<h3 id="heading-3-generative-ai">3. Generative AI</h3>
<p>SSE technology plays a key role behind the scenes when interacting with Generative AI chatbots like ChatGPT and Gemini. For instance, when a user requests ChatGPT to write an article on a specific topic, the server starts processing the request and generates the article progressively, often in chunks rather than all at once.</p>
<p>During this process, ChatGPT’s server utilizes SSE to push each part of the article to the client in real-time, allowing the user to see the content appear as it is being generated. </p>
<h2 id="heading-how-to-implement-server-sent-events-using-nodejs"><strong>How to Implement Server-Sent Events using Node.js</strong></h2>
<p>In this section, we’ll explore how to implement SSE using Node.js, a popular JavaScript runtime, to push updates to the client in real-time. We’ll set up a basic server and send live data to the browser using SSE.</p>
<p>We’ll start with the client-side (HTML/JavaScript). First, we’ll create a new <code>EventSource</code> object to listen for events from the server.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"sse-demo.js"</span>);
</code></pre>
<p>The URL <code>"sse-demo.js"</code> is the path to the server-side script that will generate the events. But if the event generator script were hosted on a different origin, we would need to provide an additional configuration for cross-origin requests.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// If the event generator script is hosted on a different origin (cross-origin request):</span>
<span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"//api.example.com/sse-demo.js"</span>, {
  <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,  <span class="hljs-comment">// Sends cookies, authorization headers with the request to the server</span>
});
</code></pre>
<p>This version ensures that cookies and authorization headers are sent with the request, enabling secure communication and making sure that credentials can be included in cross-origin requests. <code>withCredentials: true</code> ensures that authentication is handled correctly if needed.</p>
<p>Next, let’s set up an event listener to handle the message when it is received. To keep things simple, we will display the message on the user interface by adding it as a new list item.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// When a message event is received</span>
evtSource.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the message</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where messages will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Set the text content of the new list item to the message received</span>
  newElement.textContent = <span class="hljs-string">`message: <span class="hljs-subst">${event.data}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
};
</code></pre>
<p>Let's also add an event listener for a custom "ping" event. Again, we will simply add new data to the list and display it on the page. Thus, when the custom event is received, a new list item (<code>&lt;li&gt;</code>) is created.</p>
<p>The event data, which contains a <code>time</code> property, is parsed from JSON, and the time is displayed in the list item. This new list item is then appended to an unordered list (<code>&lt;ul&gt;</code>) in the HTML, allowing the "ping" event data to be shown on the user interface.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Add an event listener for a custom event type, "ping"</span>
evtSource.addEventListener(<span class="hljs-string">"ping"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the ping event</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where ping events will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Parse the event data as JSON (assuming it contains a time property)</span>
  <span class="hljs-keyword">const</span> time = <span class="hljs-built_in">JSON</span>.parse(event.data).time;

  <span class="hljs-comment">// Set the text content of the new list item to display the ping time</span>
  newElement.textContent = <span class="hljs-string">`ping at <span class="hljs-subst">${time}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
});
</code></pre>
<p>Make sure that your code for the client-side part looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a new EventSource to listen for events from the server</span>
<span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"sse-demo.js"</span>);

<span class="hljs-comment">/* If the event generator script is hosted on a different origin (cross-origin request):
const evtSource = new EventSource("//api.example.com/sse-demo.js", {
  withCredentials: true,  // Sends cookies, authorization headers with the request to the server
});
*/</span>
<span class="hljs-comment">// When a message event is received</span>
evtSource.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the message</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where messages will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Set the text content of the new list item to the message received</span>
  newElement.textContent = <span class="hljs-string">`message: <span class="hljs-subst">${event.data}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
};

<span class="hljs-comment">// Add an event listener for a custom event type, "ping"</span>
evtSource.addEventListener(<span class="hljs-string">"ping"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the ping event</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where ping events will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Parse the event data as JSON (assuming it contains a time property)</span>
  <span class="hljs-keyword">const</span> time = <span class="hljs-built_in">JSON</span>.parse(event.data).time;

  <span class="hljs-comment">// Set the text content of the new list item to display the ping time</span>
  newElement.textContent = <span class="hljs-string">`ping at <span class="hljs-subst">${time}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
});
</code></pre>
<p>Now, let’s code the server-side part with Node.js and Express.js. Express is a minimal and flexible web application framework for Node.js. It simplifies the creation of server-side applications by providing robust features like routing, middleware support, and handling HTTP requests and responses. It helps streamline the development of web APIs and websites, making it perfect for our tutorial.</p>
<p>Note that you’ll need to go to the <a target="_blank" href="https://expressjs.com">official Express.js documentation</a> and install it on your machine if you don’t have it installed already.</p>
<p>Then, head over to the IDE and import the Express module, which allows us to create an instance of the Express application.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Express module</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// Create an instance of the Express application</span>
<span class="hljs-keyword">const</span> app = express();
</code></pre>
<p>It is considered good practice to specify the port number at the top of the file to make it easy to configure and modify later. This approach improves code readability and maintainability, allowing you to quickly change the port number without searching through the entire file. It also enables better flexibility when deploying the application in different environments (for example, development, staging, production).</p>
<p>For this tutorial, we have set the port number to <code>3000</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the port number for the server to listen on</span>
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;
</code></pre>
<p>Now, let's set up the server-side part with Node.js and Express to handle SSE requests. We define a route (<code>/sse</code>) that will send a continuous stream of events to the client.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define a route that handles requests to /sse endpoint</span>
app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">//....</span>
});
</code></pre>
<p>For the server to communicate with the client using SSE, we need to set specific HTTP headers:</p>
<ul>
<li><p><strong>Content-Type</strong>: We specify <code>'text/event-stream'</code> to let the client know that the response is an SSE stream.</p>
</li>
<li><p><strong>Cache-Control</strong>: Setting it to <code>'no-cache'</code> ensures the client gets fresh data each time, without caching.</p>
</li>
<li><p><strong>Connection</strong>: This is set to <code>'keep-alive'</code> to maintain the connection open for continuous data transmission.</p>
</li>
</ul>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);
});
</code></pre>
<p>You can use <code>res.flushHeaders()</code> to send the headers immediately. Thus, the client can begin listening for events without delay.</p>
<p>To add a bit of flair, let's send a new SSE message every second, including the number of the message being sent. For this, we will initialize a variable <code>counter</code> , as well as to use <code>setInterval</code> to send a new message every second (1000ms).</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);

  <span class="hljs-comment">// Send the headers immediately, so the client starts listening for events</span>
  res.flushHeaders();

  <span class="hljs-comment">// Initialize a counter variable for the messages</span>
  <span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// Use setInterval to send a new message every second (1000ms)</span>
  <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Send a new SSE message, incrementing the counter each time</span>
    <span class="hljs-comment">// Each message is prefixed with 'data: ' and followed by the message content</span>
    res.write(<span class="hljs-string">`data: This is message <span class="hljs-subst">${counter++}</span>\n\n`</span>);
  }, <span class="hljs-number">1000</span>); <span class="hljs-comment">// This interval runs every 1000 milliseconds (1 second)</span>
});
</code></pre>
<p>The last step is to start the Express server the following way:</p>
<pre><code class="lang-javascript">app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>And that’s it! Make sure your server-sent code looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Express module</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// Create an instance of the Express application</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Define the port number for the server to listen on</span>
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Define a route that handles requests to /sse endpoint</span>
app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);

  <span class="hljs-comment">// Send the headers immediately, so the client starts listening for events</span>
  res.flushHeaders();

  <span class="hljs-comment">// Initialize a counter variable for the messages</span>
  <span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// Use setInterval to send a new message every second (1000ms)</span>
  <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Send a new SSE message, incrementing the counter each time</span>
    <span class="hljs-comment">// Each message is prefixed with 'data: ' and followed by the message content</span>
    res.write(<span class="hljs-string">`data: This is message <span class="hljs-subst">${counter++}</span>\n\n`</span>);
  }, <span class="hljs-number">1000</span>); <span class="hljs-comment">// This interval runs every 1000 milliseconds (1 second)</span>
});

<span class="hljs-comment">// Start the Express server and listen on the specified port</span>
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<h2 id="heading-websockets-vs-server-sent-events"><strong>WebSockets vs Server-Sent Events</strong></h2>
<p>The goal of data transfer methods is to load and display large datasets as quickly as possible. This ensures that the user perceives the response as instant and provides smooth navigation and a pleasant user experience.</p>
<p><a target="_blank" href="https://www.nngroup.com/articles/author/jakob-nielsen/">Jakob Nielsen</a>, a retired principal and co-founder of the Nielsen Norman Group, outlined three key time limits that developers should consider when optimizing web and application performance in his book <a target="_blank" href="https://www.nngroup.com/books/usability-engineering/">Usability Engineering</a>. In short, 0.1 seconds is the threshold for users to feel that the system is responding instantaneously, meaning that no special feedback is required other than simply displaying the result.</p>
<p><a target="_blank" href="https://www.linkedin.com/in/vera-didenko/">Vera Didenko</a>, Software Architect and Developer at Flexmonster conducted research to identify the most efficient data transfer protocol and, based on the 100-millisecond constraint, calculated the time budget for each process, ultimately choosing WebSockets as the optimal method for loading and updating the data.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe5vtbDVh_QdPm4ajDMJ3Gc2l6sF-TZs4YhzZEXLbj0fbsm1iW71lNu7X7TGuu6uUnXZSUPsPWZPjviWFcYnSZFALba9qoGgbHICv6z635gn2Ie9pvYjsv3-n0M7aZCe6Hy7kXNpC5I4P6k0YBqBcg?key=p_cDJW9Yx9AjWig3CS4ijdeZ" alt="  Extended tolerable response time from Jakob Nielsen’s “Usability Engineering”." width="600" height="400" loading="lazy"></p>
<p>For research purposes, Vera created an application using .NET Core and <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr">SignalR</a> to test and visually compare the performance of WebSockets and Server-Sent Events to discover which data transfer approach is the most performance-efficient. SignalR is an open-source library that simplifies real-time web functionality.</p>
<p>After running several tests for all methods simultaneously while increasing the number of calls each time, the test results were gathered in JSON format and fed to the <a target="_blank" href="https://www.amcharts.com/">amCharts library</a>. Below are the test results for 100, 1000, and 10000 calls:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735051327581/c940c14c-636b-4cfc-b55f-5e1fd4f11370.png" alt="The performance of WebSockets and Server-Sent Events" class="image--center mx-auto" width="1425" height="682" loading="lazy"></p>
<p>The experiment results show that WebSockets perform best for this task, emerging as the most performance-efficient data transfer technology in the simulated scenarios.</p>
<h3 id="heading-which-is-better-server-sent-events-or-websockets"><strong>Which is Better: Server-Sent Events or WebSockets?</strong></h3>
<p>SSE is a simpler solution, but it isn't extensible: if your web application <a target="_blank" href="https://www.amcharts.com/">r</a>equirements were to change, it would likely need to be refactored using WebSockets. Also, with AI integration SSE becomes even more powerful and secure.</p>
<p>Although WebSocket technology presents more upfront work, it's a more versatile and extensible framework, so it’s a better option for complex applications that are likely to add new features over time.</p>
<table><tbody><tr><td><p>Feature</p></td><td><p>WebSockets</p></td><td><p>Server-Sent Events&nbsp;</p></td></tr><tr><td><p>Communication</p></td><td><p>Full-duplex (two-way)</p></td><td><p>One-way (server-to-client)</p></td></tr><tr><td><p>Data Type Support</p></td><td><p>Binary and text</p></td><td><p>Text (UTF-8 encoded only)</p></td></tr><tr><td><p>Connection Limits</p></td><td><p>Limited by server resources</p></td><td><p>Limited by browser (e.g. 6 tabs)</p></td></tr><tr><td><p>Reconnection</p></td><td><p>Requires manual handling</p></td><td><p>Automatic</p></td></tr><tr><td><p>Protocol</p></td><td><p>Custom, low-level protocol</p></td><td><p>Built on HTTP</p></td></tr><tr><td><p>Firewall Handling</p></td><td><p>May face problems</p></td><td><p>Work seamlessly</p></td></tr><tr><td><p>Use Case Examples</p></td><td><p>real-time, event-driven communication between clients and servers, such as online games, chats, etc</p></td><td><p>streaming data uni-directionally (i.e., “one direction”) from server to client for streaming data like stock quotes, bitcoin prices, etc</p></td></tr></tbody></table>

<p>In practice, many developers prefer WebSockets even for scenarios requiring receiving information rather than opting for SSE. This preference is not solely due to the limitations of SSE—such as its reliance on keeping a connection open for continuous data flow—but also because WebSockets offer greater versatility and are often considered more future-proof.</p>
<p>For instance, popular platforms like Reddit and Trello choose WebSockets to receive data (Reddit and Trello only send information to users when they are offered to subscribe to another person).</p>
<p>From personal experience, I can point out that SSE data often doesn’t appear in the developer tools, making it harder to debug and inspect. You can verify this by checking a web application like ChatGPT, where no SSE data sent by the server is visible in the developer tools network tab. This lack of transparency can make working with SSE more challenging than the more straightforward, visible data flow provided by WebSockets.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I hope this article was both interesting and useful to you! If you want to further strengthen your knowledge and take your skills to the next level, I highly recommend diving into real-life projects.</p>
<p>Personally, I found these on freeCodeCamp to be really useful and even a bit challenging: <a target="_blank" href="https://www.freecodecamp.org/news/build-a-logging-web-app-with-server-sent-events-rxjs-and-express/">How to Build a Logging Web App with Server-Sent Events, RxJS, and Express and Learn WebSockets with Socket.IO</a>. Not only will these projects give you hands-on experience, but they will also provide you with valuable new insights and skills that you can apply to future development challenges.</p>
<p>Happy coding, and keep learning!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Build a Real-Time Multiplayer Tic-Tac-Toe Game Using WebSockets and Microservices ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, we’ll build a real-time multiplayer Tic-Tac-Toe game using Node.js, Socket.IO, and Redis. This game allows two players to connect from different browser tabs, take turns playing, and see real-time updates as they play. We'll use Red... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-real-time-multiplayer-tic-tac-toe-game-using-websockets-and-microservices/</link>
                <guid isPermaLink="false">673bb7ca83cab2eb3eafb7af</guid>
                
                    <category>
                        <![CDATA[ SocketIO ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Birkaran Sachdev ]]>
                </dc:creator>
                <pubDate>Mon, 18 Nov 2024 21:55:22 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731400068976/3c951db9-929a-4d13-ba77-759932833a9a.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, we’ll build a <strong>real-time multiplayer Tic-Tac-Toe game</strong> using <strong>Node.js</strong>, <strong>Socket.IO</strong>, and <strong>Redis</strong>. This game allows two players to connect from different browser tabs, take turns playing, and see real-time updates as they play. We'll use <strong>Redis</strong> to manage game state synchronization across multiple WebSocket servers, making our application scalable.</p>
<p>By the end, you'll have a fully functional game with real-time capabilities and a solid understanding of how to use WebSockets and Redis to build scalable real-time applications.</p>
<h3 id="heading-what-you-will-learn">What You Will Learn</h3>
<ul>
<li><p>How to use <strong>Socket.IO</strong> for real-time communication.</p>
</li>
<li><p>How to use <strong>Redis Pub/Sub</strong> to synchronize game state across multiple clients.</p>
</li>
<li><p>How to set up a scalable WebSocket server architecture.</p>
</li>
</ul>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before we start, make sure you have the following installed:</p>
<ul>
<li><p>Node.js (v16 or higher)</p>
</li>
<li><p>Redis</p>
</li>
<li><p>Docker (optional, for running Redis in a container)</p>
</li>
<li><p>Basic knowledge of JavaScript, Node.js, and WebSockets.</p>
</li>
</ul>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-project-overview">Project Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-setting-up-your-development-environment">Step 1: Setting Up Your Development Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-setting-up-the-project">Step 2: Setting Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-implementing-the-websocket-server-with-redis">Step 3: Implementing the WebSocket Server with Redis</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-implement-the-react-frontend-interface">Step 4: Implement the React Frontend interface</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-running-the-application">Step 5: Running the Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-viewing-redis-messages-in-real-time">Step 6: Viewing Redis Messages in Real-Time</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-demo">Demo</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-project-overview"><strong>Project Overview</strong></h2>
<p>We'll build a real-time Tic-Tac-Toe game with the following features:</p>
<ul>
<li><p><strong>Two players</strong> can connect and play a game.</p>
</li>
<li><p>The game board updates in real-time across different browser tabs.</p>
</li>
<li><p>The game announces a winner or declares a draw when the board is full.</p>
</li>
</ul>
<p>We’ll use:</p>
<ul>
<li><p><strong>Node.js</strong> with <strong>Socket.IO</strong> for handling WebSocket connections.</p>
</li>
<li><p><strong>Redis</strong> Pub/Sub to manage game state synchronization across clients.</p>
</li>
</ul>
<h2 id="heading-step-1-setting-up-your-development-environment"><strong>Step 1: Setting Up Your Development Environment</strong></h2>
<h3 id="heading-installing-nodejs"><strong>Installing Node.js</strong></h3>
<p>Ensure you have Node.js installed on your system:</p>
<pre><code class="lang-bash">node -v
</code></pre>
<p>If you don’t have it installed, download it from <a target="_blank" href="https://nodejs.org/en">Node.js.</a></p>
<h3 id="heading-installing-redis"><strong>Installing Redis</strong></h3>
<p>You can install Redis locally or run it in a Docker container.</p>
<h4 id="heading-macos-using-homebrew"><strong>macOS (Using Homebrew)</strong></h4>
<p>First, ensure that you have <a target="_blank" href="https://brew.sh/">Homebrew</a> installed on your system before running the commands below:</p>
<pre><code class="lang-bash">brew install redis
brew services start redis
</code></pre>
<p>Verify that the Redis container is running with the following command:</p>
<pre><code class="lang-bash">redis-cli ping
</code></pre>
<p>You should see:</p>
<pre><code class="lang-bash">PONG
</code></pre>
<h4 id="heading-using-docker-to-run-redis"><strong>Using Docker to Run Redis</strong></h4>
<pre><code class="lang-bash">docker run --name redis-server -p 6379:6379 -d redis
</code></pre>
<p>Check if Redis is running using:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -it redis-server redis-cli ping
</code></pre>
<h2 id="heading-step-2-setting-up-the-project"><strong>Step 2: Setting Up the Project</strong></h2>
<h3 id="heading-1-create-the-project-directory"><strong>1. Create the Project Directory</strong></h3>
<pre><code class="lang-bash">mkdir tic-tac-toe
<span class="hljs-built_in">cd</span> tic-tac-toe
npm init -y
</code></pre>
<h3 id="heading-2-install-dependencies"><strong>2. Install Dependencies</strong></h3>
<pre><code class="lang-bash">npm install express socket.io redis dotenv
</code></pre>
<h3 id="heading-3-create-environment-variables"><strong>3. Create Environment Variables</strong></h3>
<p>Create a <code>.env</code> file in your project root with the following contents:</p>
<pre><code class="lang-bash">PORT=3000
REDIS_HOST=localhost
REDIS_PORT=6379
</code></pre>
<h2 id="heading-step-3-implementing-the-websocket-server-with-redis"><strong>Step 3: Implementing the WebSocket Server with Redis</strong></h2>
<p>In this step, we'll set up a WebSocket server that handles real-time game interactions using <strong>Node.js</strong>, <strong>Socket.IO</strong>, and <strong>Redis</strong>. This server will manage the game state, handle player moves, and ensure synchronization across multiple clients using Redis Pub/Sub.</p>
<p>We'll break down each section of the code so you understand exactly how everything fits together.<strong>Server Code Explanation</strong></p>
<p>Create a file named <code>server.js</code> and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">'dotenv'</span>;
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> http <span class="hljs-keyword">from</span> <span class="hljs-string">'http'</span>;
<span class="hljs-keyword">import</span> { Server } <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io'</span>;
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'redis'</span>;

dotenv.config(); <span class="hljs-comment">// Load environment variables from .env file</span>

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> server = http.createServer(app);
<span class="hljs-keyword">const</span> io = <span class="hljs-keyword">new</span> Server(server, {
  <span class="hljs-attr">cors</span>: {
    <span class="hljs-attr">origin</span>: <span class="hljs-string">"http://localhost:5173"</span>,
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>],
  }
});
</code></pre>
<ul>
<li><p><strong>dotenv</strong>: Loads environment variables from a <code>.env</code> file to keep sensitive information like ports and keys secure.</p>
</li>
<li><p><strong>express</strong>: Sets up a basic Express server to handle HTTP requests.</p>
</li>
<li><p><strong>http</strong>: We create an HTTP server using Node's built-in <code>http</code> module, which we'll use with <strong>Socket.IO</strong> for WebSocket communication.</p>
</li>
<li><p><strong>Socket.IO</strong>: This library enables real-time, bidirectional communication between the server and clients.</p>
</li>
<li><p><strong>CORS Configuration</strong>: Allows cross-origin requests from our frontend running on <code>localhost:5173</code>.</p>
</li>
</ul>
<p>Then, to create Redis publisher and subscriber clients, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Initialize Redis clients</span>
<span class="hljs-keyword">const</span> pubClient = createClient();
<span class="hljs-keyword">const</span> subClient = createClient();
<span class="hljs-keyword">await</span> pubClient.connect();
<span class="hljs-keyword">await</span> subClient.connect();
</code></pre>
<p>We use <strong>Redis</strong> to handle real-time data synchronization between connected clients.</p>
<ul>
<li><p><strong>pubClient</strong>: Used to publish messages (like game state updates).</p>
</li>
<li><p><strong>subClient</strong>: Subscribes to messages (listens for updates).</p>
</li>
</ul>
<ul>
<li><strong>connect()</strong>: Establishes a connection to the Redis server.</li>
</ul>
<p>In this paradigm, one client is used to publish updates, and the other one subscribes to updates. This helps avoid blocking behavior, since Redis clients in <strong>subscribe</strong> mode can only receive messages.</p>
<p>To subscribe to Redis channels for game updates, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Subscribe to the Redis channel for game updates</span>
<span class="hljs-keyword">await</span> subClient.subscribe(<span class="hljs-string">'game-moves'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
  gameState = <span class="hljs-built_in">JSON</span>.parse(message);
  io.emit(<span class="hljs-string">'gameState'</span>, gameState);
});
</code></pre>
<ul>
<li><p><strong>subClient.subscribe</strong>: Listens for messages on the <code>game-moves</code> channel.</p>
</li>
<li><p>Whenever a new move is made by a player, the game state is updated in Redis, and all connected clients are informed of the new state.</p>
</li>
<li><p>The <code>message</code> parameter contains the game state as a string. We parse it into a JavaScript object and broadcast the updated state using <strong>Socket.IO</strong>.</p>
</li>
</ul>
<p>Next, to define the game state and functions, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define initial game state</span>
<span class="hljs-keyword">let</span> gameState = {
  <span class="hljs-attr">board</span>: <span class="hljs-built_in">Array</span>(<span class="hljs-number">9</span>).fill(<span class="hljs-literal">null</span>),
  <span class="hljs-attr">xIsNext</span>: <span class="hljs-literal">true</span>,
};

<span class="hljs-comment">// Function to reset the game</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resetGame</span>(<span class="hljs-params"></span>) </span>{
  gameState = {
    <span class="hljs-attr">board</span>: <span class="hljs-built_in">Array</span>(<span class="hljs-number">9</span>).fill(<span class="hljs-literal">null</span>),
    <span class="hljs-attr">xIsNext</span>: <span class="hljs-literal">true</span>,
  };
}
</code></pre>
<ul>
<li><p><strong>gameState</strong>: Keeps track of the current state of the board and whose turn it is (<code>xIsNext</code>).</p>
<ul>
<li><p>The board is represented as an array of 9 cells (each can be 'X', 'O', or <code>null</code>).</p>
</li>
<li><p>The <code>xIsNext</code> flag determines which player's turn it is.</p>
</li>
</ul>
</li>
<li><p><strong>resetGame()</strong>: Resets the board and turn indicator to their initial state, allowing for a new game to start.</p>
</li>
</ul>
<p>Next, to handle WebSocket connections, let’s add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript">io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'New client connected:'</span>, socket.id);

  <span class="hljs-comment">// Send the current game state to the newly connected client</span>
  socket.emit(<span class="hljs-string">'gameState'</span>, gameState);
</code></pre>
<ul>
<li><p>The <code>io.on('connection')</code> event is triggered when a new client connects.</p>
</li>
<li><p><strong>socket.id</strong>: A unique identifier for each connected client.</p>
</li>
<li><p>We immediately send the current <code>gameState</code> to the new client so they can see the current board.</p>
</li>
</ul>
<p>To handle player moves, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// Handle player moves</span>
  socket.on(<span class="hljs-string">'makeMove'</span>, <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-comment">// Prevent making a move if cell is already taken or game is over</span>
    <span class="hljs-keyword">if</span> (gameState.board[index] || calculateWinner(gameState.board)) <span class="hljs-keyword">return</span>;

    <span class="hljs-comment">// Update the board and switch turns</span>
    gameState.board[index] = gameState.xIsNext ? <span class="hljs-string">'X'</span> : <span class="hljs-string">'O'</span>;
    gameState.xIsNext = !gameState.xIsNext;

    <span class="hljs-comment">// Publish the updated game state to Redis</span>
    pubClient.publish(<span class="hljs-string">'game-moves'</span>, <span class="hljs-built_in">JSON</span>.stringify(gameState));
    io.emit(<span class="hljs-string">'gameState'</span>, gameState);
  });
</code></pre>
<ul>
<li><p><strong>makeMove</strong>: This event is triggered when a player clicks on a cell.</p>
<ul>
<li><p><strong>Validation</strong>: We check if the cell is already occupied or if the game has ended before making a move.</p>
</li>
<li><p><strong>Updating Game State</strong>: If the move is valid, we update the board and switch turns.</p>
</li>
</ul>
</li>
<li><p>The updated game state is then:</p>
<ol>
<li><p><strong>Published to Redis</strong>: This ensures that all instances of the server stay in sync.</p>
</li>
<li><p><strong>Broadcasted to all clients</strong>: This immediately updates the game board for all players.</p>
</li>
</ol>
</li>
</ul>
<p>To handle game restarts, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Handle game restarts</span>
socket.on(<span class="hljs-string">'restartGame'</span>, <span class="hljs-function">() =&gt;</span> {
  resetGame();
  io.emit(<span class="hljs-string">'gameState'</span>, gameState);
});
</code></pre>
<p>To handle client disconnection handling, we’ll add the following code to <code>server.js</code>:</p>
<pre><code class="lang-javascript"> socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client disconnected:'</span>, socket.id);
  });
});
</code></pre>
<p>Finally, to process the logic of the game, we’ll add the following functions to <code>server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Function to check if there's a winner</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateWinner</span>(<span class="hljs-params">board</span>) </span>{
  <span class="hljs-keyword">const</span> lines = [
    [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>], [<span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>],
    [<span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">7</span>], [<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>],
    [<span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">8</span>], [<span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">6</span>]
  ];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> [a, b, c] <span class="hljs-keyword">of</span> lines) {
    <span class="hljs-keyword">if</span> (board[a] &amp;&amp; board[a] === board[b] &amp;&amp; board[a] === board[c]) {
      <span class="hljs-keyword">return</span> board[a];
    }
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isBoardFull</span>(<span class="hljs-params">board</span>) </span>{
  <span class="hljs-keyword">return</span> board.every(<span class="hljs-function">(<span class="hljs-params">cell</span>) =&gt;</span> cell !== <span class="hljs-literal">null</span>);
}
</code></pre>
<ul>
<li><p><strong>calculateWinner()</strong>: Checks if there’s a winning combination on the board.</p>
</li>
<li><p><strong>isBoardFull()</strong>: Checks if all cells are filled, indicating a draw.</p>
</li>
</ul>
<h2 id="heading-step-4-implement-the-react-frontend-interface"><strong>Step 4: Implement the React Frontend interface</strong></h2>
<p>In this step, we build a simple and interactive React frontend for our Tic-Tac-Toe game. This frontend allows players to connect to the WebSocket server, make moves, and see the game board update in real-time.</p>
<p>In <code>App.jsx</code>, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;

<span class="hljs-keyword">const</span> socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [gameState, setGameState] = useState({
    <span class="hljs-attr">board</span>: <span class="hljs-built_in">Array</span>(<span class="hljs-number">9</span>).fill(<span class="hljs-literal">null</span>),
    <span class="hljs-attr">xIsNext</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">winner</span>: <span class="hljs-literal">null</span>
  });

  useEffect(<span class="hljs-function">() =&gt;</span> {
    socket.on(<span class="hljs-string">'gameState'</span>, <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> {
      setGameState(state);
    });

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> socket.off(<span class="hljs-string">'gameState'</span>);
  }, []);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (gameState.board[index] || gameState.winner) <span class="hljs-keyword">return</span>;
    socket.emit(<span class="hljs-string">'makeMove'</span>, index);
  };

  <span class="hljs-keyword">const</span> renderCell = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleClick(index)}&gt;{gameState.board[index]}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Multiplayer Tic-Tac-Toe<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"board"</span>&gt;</span>
        {[...Array(9)].map((_, i) =&gt; renderCell(i))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> socket.emit('restartGame')}&gt;Restart Game<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here is a summary of how the React app is broken down:</p>
<ul>
<li><p><strong>WebSocket Connection</strong>:</p>
<ul>
<li>The frontend establishes a connection to the server using <code>socket.io-client</code>.</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>State Management</strong>:</p>
<ul>
<li><p>The game state (<code>gameState</code>) is managed with React's <code>useState</code> and includes:</p>
<ul>
<li><p>The <strong>board</strong> (9 cells).</p>
</li>
<li><p>The flag <strong>xIsNext</strong> to indicate the current player's turn.</p>
</li>
<li><p>The <strong>winner</strong> status.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Real-Time Updates</strong>:</p>
<ul>
<li><p>The <code>useEffect</code> hook:</p>
<ul>
<li><p>Listens for <code>gameState</code> updates from the server.</p>
</li>
<li><p>Updates the local game state when changes are detected.</p>
</li>
<li><p>Cleans up the WebSocket listener when the component is unmounted.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Handling Player Moves</strong>:</p>
<ul>
<li><p>The <code>handleClick</code> function:</p>
<ul>
<li><p>Checks if a cell is already occupied or if the game has a winner before allowing a move.</p>
</li>
<li><p>Sends a <code>makeMove</code> event to the server with the clicked cell index.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Game Board Rendering</strong>:</p>
<ul>
<li><p>The <code>renderCell</code> function creates a button for each cell on the board.</p>
</li>
<li><p>The board is displayed using a 3x3 grid.</p>
</li>
</ul>
</li>
<li><p><strong>Restart Game</strong>:</p>
<ul>
<li>The "Restart Game" button emits a <code>restartGame</code> event to reset the game board for all players.</li>
</ul>
</li>
<li><p><strong>User Interface</strong>:</p>
<ul>
<li>A simple and interactive layout that allows players to take turns and see updates in real-time.</li>
</ul>
</li>
</ul>
<h2 id="heading-step-5-running-the-application"><strong>Step 5: Running the Application</strong></h2>
<h3 id="heading-starting-the-backend"><strong>Starting the Backend</strong></h3>
<p>To start the backend server, open a new terminal window and run the following commands:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> tic-tac-toe
npm start
</code></pre>
<h3 id="heading-starting-the-frontend"><strong>Starting the Frontend</strong></h3>
<p>To start the React frontend server, open a new terminal window and run the commands below (do not use the same one which the backend server is running on, as you need both running simultaneously to run the game).</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> tic-tac-toe-client
npm run dev
</code></pre>
<h3 id="heading-accessing-the-game"><strong>Accessing the Game</strong></h3>
<p>Open your browser and navigate to:</p>
<pre><code class="lang-bash">http://localhost:5173
</code></pre>
<h2 id="heading-step-6-viewing-redis-messages-in-real-time"><strong>Step 6: Viewing Redis Messages in Real-Time</strong></h2>
<p>While the game is running, you can view Redis messages to see real-time game state updates.</p>
<p>Open a terminal and run:</p>
<pre><code class="lang-bash">redis-cli
SUBSCRIBE game-moves
</code></pre>
<p>This will display game updates:</p>
<pre><code class="lang-bash">1) <span class="hljs-string">"message"</span>
2) <span class="hljs-string">"game-moves"</span>
3) <span class="hljs-string">"{\"board\":[\"X\",null,\"O\",null,\"X\",null,null,null,null],\"xIsNext\":false}"</span>
</code></pre>
<p>Every time a move is made or the game state changes, the server publishes the updated game state to the <code>game-moves</code> channel. Using <code>redis-cli</code>, you can monitor these updates in real-time, as the game is being played.</p>
<h2 id="heading-demo"><strong>Demo</strong></h2>
<p>In this demo, you'll see the Tic Tac Toe game running locally, demonstrating real-time updates as players take turns.</p>
<p>The gameplay showcases features such as turn switching, board updates, and game state announcements (winner or draw). This highlights how the game leverages WebSocket communication to provide a smooth, interactive experience.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/2aCllaBR6Xg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Congratulations, you’ve successfully built a real-time multiplayer Tic-Tac-Toe game using Node.js, Socket.IO, and Redis. Here’s what you’ve learned:</p>
<ul>
<li><p>Real-time WebSocket communication using <strong>Socket.IO</strong>.</p>
</li>
<li><p>Game state management using <strong>Redis Pub/Sub</strong>.</p>
</li>
<li><p>Building a responsive front-end with <strong>React</strong>.</p>
</li>
</ul>
<h3 id="heading-next-steps"><strong>Next Steps</strong></h3>
<ul>
<li><p>Add player authentication.</p>
</li>
<li><p>Implement a chat feature.</p>
</li>
<li><p>Deploy your application to a cloud provider for scalability.</p>
</li>
</ul>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Server-Sent Events in Go ]]>
                </title>
                <description>
                    <![CDATA[ Server-Sent Events (SSE) is a powerful technology that enables real-time, unidirectional communication from servers to clients. In this article, we'll explore how to implement SSE in Go, discussing its benefits, use cases, and providing practical exa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-server-sent-events-in-go/</link>
                <guid isPermaLink="false">66cf2f37fda106b7e106dff1</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Pliutau ]]>
                </dc:creator>
                <pubDate>Wed, 28 Aug 2024 14:07:51 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724762290560/de9c7afd-2a81-4bd6-aa12-da92a759ebdb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Server-Sent Events (SSE) is a powerful technology that enables real-time, unidirectional communication from servers to clients.</p>
<p>In this article, we'll explore how to implement SSE in Go, discussing its benefits, use cases, and providing practical examples. By the end, you should know the basics of building real-time applications with efficient, unidirectional communication.</p>
<h2 id="heading-what-are-server-sent-events">What are Server-Sent Events?</h2>
<p>SSE is a web technology that allows servers to push data to clients over a single HTTP connection.</p>
<p>Unlike WebSockets, SSE is unidirectional, making it simpler to implement and ideal for scenarios where real-time updates from the server are required, but client-to-server communication is not necessary.</p>
<p>Developing a web application that uses SSE is straightforward. You'll need a bit of code on the server to stream events to the front-end, but the client side code works almost identically to websockets when it comes to handling incoming events. This is a one-way connection, so you can't send events from a client to a server.</p>
<h3 id="heading-benefits-of-sse">Benefits of SSE</h3>
<ol>
<li><p><strong>Simplicity</strong>: SSE is easier to implement compared to WebSockets.</p>
</li>
<li><p><strong>Native browser support</strong>: Most modern browsers support SSE out of the box.</p>
</li>
<li><p><strong>Automatic reconnection</strong>: Clients automatically attempt to reconnect if the connection is lost.</p>
</li>
<li><p><strong>Efficient</strong>: Uses a single HTTP connection, reducing overhead.</p>
</li>
</ol>
<h2 id="heading-how-to-implement-sse-in-go">How to Implement SSE in Go</h2>
<p>For our example here, we'll create a simple SSE server in Go which just sends the data to the client every second with a current timestamp. The client can then connect to our server on port 8080 and receive these messages.</p>
<p>A real example could be something more sophisticated like sending notifications, displaying progress bar updates, and so on.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sseHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    <span class="hljs-comment">// Set http headers required for SSE</span>
    w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"text/event-stream"</span>)
    w.Header().Set(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"no-cache"</span>)
    w.Header().Set(<span class="hljs-string">"Connection"</span>, <span class="hljs-string">"keep-alive"</span>)

    <span class="hljs-comment">// You may need this locally for CORS requests</span>
    w.Header().Set(<span class="hljs-string">"Access-Control-Allow-Origin"</span>, <span class="hljs-string">"*"</span>)

    <span class="hljs-comment">// Create a channel for client disconnection</span>
    clientGone := r.Context().Done()

    rc := http.NewResponseController(w)
    t := time.NewTicker(time.Second)
    <span class="hljs-keyword">defer</span> t.Stop()
    <span class="hljs-keyword">for</span> {
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> &lt;-clientGone:
            fmt.Println(<span class="hljs-string">"Client disconnected"</span>)
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">case</span> &lt;-t.C:
            <span class="hljs-comment">// Send an event to the client</span>
            <span class="hljs-comment">// Here we send only the "data" field, but there are few others</span>
            _, err := fmt.Fprintf(w, <span class="hljs-string">"data: The time is %s\n\n"</span>, time.Now().Format(time.UnixDate))
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                <span class="hljs-keyword">return</span>
            }
            err = rc.Flush()
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                <span class="hljs-keyword">return</span>
            }
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    http.HandleFunc(<span class="hljs-string">"/events"</span>, sseHandler)
    fmt.Println(<span class="hljs-string">"server is running on :8080"</span>)
    <span class="hljs-keyword">if</span> err := http.ListenAndServe(<span class="hljs-string">":8080"</span>, <span class="hljs-literal">nil</span>); err != <span class="hljs-literal">nil</span> {
        fmt.Println(err.Error())
    }
}
</code></pre>
<h3 id="heading-key-components-of-the-sse-implementation"><strong>Key Components of the SSE Implementation</strong></h3>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format">event stream</a> is a simple stream of text data which must be encoded using UTF-8. Messages in the event stream are separated by a pair of newline characters – <strong>\n\n</strong>. A colon as the first character of a line is in essence a comment, and is ignored.</p>
<p>In our server it is done here:</p>
<pre><code class="lang-go">rc := http.NewResponseController(w)
fmt.Fprintf(w, <span class="hljs-string">"data: The time is %s\n\n"</span>, time.Now().Format(time.UnixDate))
<span class="hljs-comment">// To make sure that the data is sent immediately</span>
rc.Flush()
</code></pre>
<p>The server that sends events needs to respond using the MIME type <strong>text/event-stream.</strong> We do it by setting the response header here:</p>
<pre><code class="lang-go">w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"text/event-stream"</span>)
</code></pre>
<p>You may have noticed that we set few other headers as well. One is to keep the HTTP connection open, and another to bypass CORS:</p>
<pre><code class="lang-go">w.Header().Set(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"no-cache"</span>)
w.Header().Set(<span class="hljs-string">"Connection"</span>, <span class="hljs-string">"keep-alive"</span>)
w.Header().Set(<span class="hljs-string">"Access-Control-Allow-Origin"</span>, <span class="hljs-string">"*"</span>)
</code></pre>
<p>And the last important piece is to detect the disconnect. In Go, we'll receive it as a message in a specified channel:</p>
<pre><code class="lang-go">clientGone := r.Context().Done()

<span class="hljs-keyword">for</span> {
    <span class="hljs-keyword">select</span> {
    <span class="hljs-keyword">case</span> &lt;-clientGone:
        fmt.Println(<span class="hljs-string">"Client disconnected"</span>)
        <span class="hljs-keyword">return</span>
    }
}
</code></pre>
<p>Each message received has some combination of the following fields, one per line. In our server we send only the data field which is enough, as other fields are optional. More details <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">here</a>.</p>
<ul>
<li><p><strong>event</strong> – a string identifying the type of event described.</p>
</li>
<li><p><strong>data</strong> – the data field for the message.</p>
</li>
<li><p><strong>id</strong> – the event ID to set the EventSource object's last event ID value.</p>
</li>
<li><p><strong>retry</strong> – the reconnection time.</p>
</li>
</ul>
<h3 id="heading-how-to-receive-the-events-on-the-client-side">How to Receive the Events on the Client Side</h3>
<p>On the front end or client side, you will have to use the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#creating_an_eventsource_instance">EventSource</a> interface. It's a browser API encapsulating Server-Sent Events. In the following example, our browser application receives the events from the server and prints them in a list.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"list"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
        <span class="hljs-keyword">const</span> eventSrc = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"http://127.0.0.1:8080/events"</span>);

        <span class="hljs-keyword">const</span> list = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

        eventSrc.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> li = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);
            li.textContent = <span class="hljs-string">`message: <span class="hljs-subst">${event.data}</span>`</span>;

            list.appendChild(li);
        };
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Here is how it may look in your browser:</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2cda643-36a6-4986-8100-76d1d7c3fb33_998x490.png" alt="logs" width="998" height="490" loading="lazy"></p>
<h2 id="heading-best-practices-for-sse-in-golang"><strong>Best Practices for SSE in Golang</strong></h2>
<h3 id="heading-event-formatting"><strong>Event Formatting</strong></h3>
<p>In a real world project, a simple string of data may not be enough. In these cases, using a structured format like JSON can be a good option to send multiple data fields once. Here's an example:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"status"</span>: <span class="hljs-string">"in_progress"</span>,
  <span class="hljs-attr">"completion"</span>: <span class="hljs-number">51.22</span>
}
</code></pre>
<h3 id="heading-reconnection-strategy-and-error-handling"><strong>Reconnection Strategy and Error Handling</strong></h3>
<p>Something could always go wrong on both sides: the server might reject the connection for some reason or a client might abruptly disconnect.</p>
<p>In each case, you'll need to implement a backoff strategy for graceful reconnections. It's better to miss one message than completely break the event loop.</p>
<p>In JavaScript, you can check for errors in EventSource and then act accordingly:</p>
<pre><code class="lang-javascript">eventSrc.onerror = <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"EventSource failed:"</span>, err);
};
</code></pre>
<h3 id="heading-load-balancing"><strong>Load Balancing</strong></h3>
<p>For high-traffic applications, you may consider using a Load Balancer, for example NGINX. If you plan to have many clients connecting to your server, it's good to test it beforehand by simulating the load from the clients.</p>
<h2 id="heading-use-cases-for-sse"><strong>Use Cases for SSE</strong></h2>
<ol>
<li><p>Real-time dashboards</p>
</li>
<li><p>Live sports scores</p>
</li>
<li><p>Social media feeds</p>
</li>
<li><p>Stock market tickers</p>
</li>
<li><p>Progress indicators for long-running tasks</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Server-Sent Events provide an efficient and straightforward way to implement real-time, server-to-client communication in Golang applications. By leveraging SSE, developers can create responsive and dynamic web applications with minimal overhead and complexity.</p>
<p>As you build your SSE-powered applications, remember to consider scalability, error handling, and client-side implementation to ensure a robust and efficient real-time communication system.</p>
<p><a target="_blank" href="https://packagemain.tech">Explore more articles from packagemain.tech</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
