Getting Started with Server-Sent Events (SSE) using Express.js and EventSource
Tags: javascript, webdev, beginners, html
Published: 2024-06-24 22:08:45

Server-Sent Events (SSE) is a technology that allows a server to push updates to the client over a single HTTP connection. It's a great way to handle real-time data in web applications, offering a simpler alternative to WebSockets for many use cases.

If you prefer watching a tutorial, you can watch the accompanying video here. The video provides a step-by-step guide and further explanations to help you understand SSE better. It goes into more details than the written tutorial below.

{% embed https://youtu.be/ieUsuDsQY0o %}

## Understanding HTTP Requests and Responses

First, let's take a look at how a typical set of HTTP requests and responses work. In the diagram below, you can see that the client opens a connection for a resource such as an image, HTML file, or API call. The client then receives a response, and the connection closes. The client can then open another connection to make another request and receive a response, at which point the connection closes again.

![HTTP Request Response Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ksfcw9g5nbsjdb935bk1.png)

## Understanding Server-Sent Events (SSE)

With Server-Sent Events (SSE), a client can open a connection with a request and keep that connection open to receive multiple responses from the server. Once the connection is open, the communication direction is one-way: from the server to the client. The client cannot make additional requests over the same connection.

The client initiates the connection with a request using an `Accept` header of `text/event-stream`. The server responds with a `Content-Type` of `text/event-stream` and typically uses `Transfer-Encoding: chunked`. This encoding allows the server to send multiple chunks of data without knowing the total size of the response beforehand.

In the diagram below, you can see how the SSE connection is established and how data flows from the server to the client:

![Server Sent Events Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tkayop0rl7syzluxr7v.png)

## Project Structure
We'll be organizing our project into two main folders: server for the backend and client for the frontend.

```
sse-example/
├── client/
│   ├── index.html
│   └── index.js
└── server/
    ├── index.js
    └── package.json
```

## Setting Up the Server
First, we'll create an Express.js server that can handle SSE connections. You'll need Node.js installed on your machine. Navigate to the server folder and initialize a new Node.js project:

```
mkdir server
cd server
npm init -y
```

Install the necessary dependencies:

```
npm install express cors
npm install --save-dev nodemon
```

To use ES6 imports, make sure your package.json includes "type": "module":

package.json
```
{
  "name": "sse-example",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "nodemon index.js"
  },
  "dependencies": {
    "express": "^4.17.1",
    "cors": "^2.8.5"
  },
  "devDependencies": {
    "nodemon": "^2.0.7"
  }
}
```

Next, create a file called index.js in the server folder and add the following code:

```
import express from 'express';
import cors from 'cors';

const app = express();
const port = 3000;

app.use(cors());

app.get('/currentTime', (req, res) => {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    const intervalId = setInterval(() => {
        res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);
    }, 1000);

    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});
```

In this code, we create an Express.js server that listens for GET requests on the /currentTime endpoint. The server sets the necessary headers for SSE and sends a timestamp to the client every second as a simple string. We also handle client disconnections by clearing the interval and ending the response.

## Setting Up the Client

For the client side, we'll use a simple HTML file and JavaScript to handle the SSE stream. Create a client folder and create the following files index.html and index.js as per the file structure:

```
sse-example/
├── client/        <-- Here
│   ├── index.html <-- Here
│   └── index.js   <-- Here
└── server/
    ├── index.js
    └── package.json
```
index.html
```
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script defer src="index.js"></script>
    <style>
      body {
        background-color: black;
        color: white;
      }
    </style>
  </head>
  <body>
    <h1 id="time">Time</h1>
  </body>
</html>
```

index.js
```
const eventSource = new EventSource('http://localhost:3000/currentTime');

eventSource.onmessage = function(event) {
    document.getElementById('time').textContent = `${event.data}`;
};

eventSource.onerror = function() {
    console.log("EventSource failed.");
};
```

In this HTML and JavaScript setup, we create a connection to the server using EventSource and update the time displayed in the DOM as new messages are received. We also handle any errors that might occur with the EventSource connection.


## Running the Example

To run the example, start the Express.js server by executing:

```
cd server
npm start
```

Then, open index.html using VS Code Live Server extension. Install VS  Code Live server if you have not already by going to the extensions tab and finding `live server` and clicking install. Once installed right click the index.Html file and click `Open With Live Server`. Your default browser will open and you should see see the time being updated every second.

## Conclusion

Server-Sent Events provide an efficient way to handle real-time updates in web applications. With just a few lines of code, you can set up an SSE server and client to stream data seamlessly. Give it a try in your next project and enjoy the simplicity and power of SSE!

Feel free to reach out with any questions or feedback in the comments below. Happy coding!