logo My Digital Garden

Server Sent Events from Node in Express

By James Kolean on May 20, 2023
Source repository: https://gitlab.com/jameskolean/simple-node-server-sent-events
JavaScript
banner

In today’s fast-paced digital landscape, real-time communication and instant updates have become paramount for web applications. Users expect timely information and dynamic content that responds to their actions without constant page refreshes. To fulfill these expectations, developers have turned to various technologies, and one such solution that has gained popularity is Server-Sent Events (SSE).

Server-Sent Events is a simple yet powerful technology allowing servers to push real-time client updates over HTTP connections. It enables web applications to establish a persistent, one-way communication channel between the server and the client, facilitating the effortless delivery of data as soon as it becomes available. SSE offers a streamlined solution for creating responsive, event-driven applications, whether it’s stock market updates, social media feeds, or collaborative document editing.

Unlike other real-time communication technologies, such as WebSockets or polling, SSE is built on top of standard HTTP protocol, making it compatible with most web servers, browsers, and infrastructure setups. It is a unidirectional protocol, meaning the server can initiate communication anytime, sending data to connected clients without requiring client-side requests. This approach reduces unnecessary network traffic and server load, providing a more efficient and scalable solution for real-time applications.

One of the significant advantages of SSE is its simplicity. It employs a straightforward API, making it easy to implement and understand, even for developers new to real-time web applications. The API revolves around “event streams, ” where the server sends a series of events to the client. Each event has a unique event ID, an event type, and a data payload. Clients can listen for specific event types or capture all events, processing them accordingly.

Another essential feature of SSE is its built-in support for automatic reconnection. SSE handles the reconnection process seamlessly, ensuring uninterrupted data delivery if a connection between the client and the server is lost due to network disruptions or server-side restarts. This robustness guarantees a reliable real-time user experience, enhancing web applications’ overall performance and responsiveness.

This example comes from https://www.digitalocean.com/community/tutorials/nodejs-server-sent-events-build-realtime-app

The example uses an Express server, and there are two key sections. The First section manages the connected clients and looks like this.

// Manage the connection to the clients - START
function eventsHandler(request, response, next) {
    const headers = {
        "Content-Type": "text/event-stream",
        Connection: "keep-alive",
        "Cache-Control": "no-cache",
    };
    response.writeHead(200, headers);

    const data = `data: ${JSON.stringify(facts)}\n\n`;

    response.write(data);

    const clientId = Date.now();

    const newClient = {
        id: clientId,
        response,
    };

    clients.push(newClient);

    request.on("close", () => {
        console.log(`${clientId} Connection closed`);
        clients = clients.filter((client) => client.id !== clientId);
    });
}
app.get("/events", eventsHandler);
// Manage the connection to the clients - END

The second section ingests data and pushes it to clients.

// Ingest facts and push to clients - START
function sendEventsToAll(newFact) {
    clients.forEach((client) =>
        client.response.write(`data: ${JSON.stringify(newFact)}\n\n`)
    );
}
async function addFact(request, respsonse, next) {
    const newFact = request.body;
    facts.push(newFact);
    respsonse.json(newFact);
    return sendEventsToAll(newFact);
}
app.post("/fact", addFact);
// Ingest facts and push to clients - END

You can run this from the command line like this:

cd server
npm install
npm run dev
curl -H Accept:text/event-stream http://localhost:3001/events

In another terminal post a fact like this.

curl -X POST \
 -H "Content-Type: application/json" \
 -d '{"info": "Its impossible to hum while holding your nose.", "source": "https://www.rd.com/list/weird-facts/"}'\
 -s http://localhost:3001/fact

Let’s create a React to connect to the server. The interesting section of the React app looks like this from App.js.

  const [facts, setFacts] = useState([]);
  const [listening, setListening] = useState(false);

  useEffect(() => {
      if (!listening) {
          const events = new EventSource("http://localhost:3001/events");
          events.onmessage = (event) => {
              const parsedData = JSON.parse(event.data);
              setFacts((facts) => facts.concat(parsedData));
          };
          setListening(true);
      }
  }, [listening, facts]);

You can run this from a new terminal session like this:

cd client
npm install
npm start

That’s all there is to it.

© Copyright 2023 Digital Garden cultivated by James Kolean.