DEV Community

Cover image for Server side events using nodeJS
devashishSarmah
devashishSarmah

Posted on

Server side events using nodeJS

Server-Sent Events (SSE) is a technology based on HTTP. On the client-side, it provides an API called EventSource (part of the HTML5 standard) that allows us to connect to the server and receive updates from it.

Let's create a simple chat system

First, we are gonna create a new nodeJS project

Let's name it sse-server

Now, let's initiate npm to install some dependencies

Initiate NPM

We are gonna add express, body-parser and cors

NPM Install command

In index.ts

  • Configure the middleware
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';

const app = express();

app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
Enter fullscreen mode Exit fullscreen mode
  • Specify the PORT
const PORT = 3000;
Enter fullscreen mode Exit fullscreen mode
  • Declare and initialise the required variables
// Contains the connected clients info
let clients: any[] = []; 
// Contains the messages of the network
const messages: any[] = [];
Enter fullscreen mode Exit fullscreen mode
  • Create a endpoint where the clients will subscribe to events
app.get('/messages', (request: any, response: any) => {
  const headers: any = {
    'Content-Type': 'text/event-stream',
    Connection: 'keep-alive',
    'Cache-Control': 'no-cache'
  };

  response.writeHead(200, headers);

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

  response.write(data);

  const clientId = (request.query.id ?? 'guest') + '_' + Date.now();

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

  clients.push(newClient);

  request.on('close', () => {
    console.log(`${clientId} Connection closed`);
    clients = clients.filter((client: any) => client.id !== clientId);
  });
});
Enter fullscreen mode Exit fullscreen mode
  • A function to notify whenever a new message arrives in the network
const notifyMessageToAllUsers = (userIdWithoutUnderscore: string) => {
  clients
    .filter(
      (client: any) =>
        String(client.id).split('_')[0] != userIdWithoutUnderscore
    )
    .forEach((client: any) => {
      client.response.write(`data: ${JSON.stringify(messages)}\n\n`);
    });
};
Enter fullscreen mode Exit fullscreen mode
  • Finally an endpoint to push messages to the network
app.post('/message', (request, response) => {
  if (
    request.query.id &&
    request.body &&
    request.body.message &&
    String(request.body.message).trim()
  ) {
    messages.push({
      user_id: request.query.id,
      message: request.body.message.trim()
    });
    notifyMessageToAllUsers(String(request.query.id));
    response.send({ status: 200, error: 'Message Sent Succesfully' });
  } else {
    response.send({ status: 400, error: 'Bad Request' });
  }
});
Enter fullscreen mode Exit fullscreen mode
  • let's start the server
app.listen(PORT, () => {
  console.log(`Server is listening at http://localhost:${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
$ npm start
Enter fullscreen mode Exit fullscreen mode

Server console

$ Server is listening at http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

For pushing a message to the network

$ curl --location --request POST 'http://localhost:3000/message?id=1234' \
--header 'Content-Type: application/json' \
--data-raw '{
    "message": "Hi"
}'
Enter fullscreen mode Exit fullscreen mode

To listen to the messages

curl --location --request GET 'http://localhost:3000/messages' \
--header 'Accept: text/event-stream'
Enter fullscreen mode Exit fullscreen mode

After subscribing to the endpoint, we should be able to see the message that was pushed earlier

$ data: [{"user_id":"1234","message":"Hi"}]
Enter fullscreen mode Exit fullscreen mode

Conclusion

SSE is very powerful in terms of receiving events from the server to achieve real-time behaviour in the client. But it can get very expensive if it's not implemented efficiently.

Thanks for Reading!

Thanks for reading, I hope you enjoyed it!

Top comments (0)