Websockets with React & Express [Part-1]
Tags: webdev, websocket, javascript
Published: 2020-05-09 14:03:03

A quick tutorial on setting up websockets on a react + express app. This tutorial assumes you already have a running react client and express server.

If you are new to websockets and would like to know how it works, I recommend reading this post - [Websockets 101](https://lucumr.pocoo.org/2012/9/24/websockets-101/)


### WebSocket server

We'll be using [ws](https://www.npmjs.com/package/ws) package to setup the websocket server. First let's write a websocket setup function.

```javascript
// setupWebSocket.js
const WebSocket = require("ws");

// accepts an http server (covered later)
function setupWebSocket(server) {
  // ws instance
  const wss = new WebSocket.Server({ noServer: true });

  // handle upgrade of the request
  server.on("upgrade", function upgrade(request, socket, head) {
    try {
       // authentication and some other steps will come here
       // we can choose whether to upgrade or not

       wss.handleUpgrade(request, socket, head, function done(ws) {
        wss.emit("connection", ws, request);
       });
    } catch (err) {
      console.log("upgrade exception", err);
      socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
      socket.destroy();
      return;
    }
  });

  // what to do after a connection is established
  wss.on("connection", (ctx) => {
    // print number of active connections
    console.log("connected", wss.clients.size);

    // handle message events
    // receive a message and echo it back
    ctx.on("message", (message) => {
      console.log(`Received message => ${message}`);
      ctx.send(`you said ${message}`);
    });

    // handle close event
    ctx.on("close", () => {
      console.log("closed", wss.clients.size);
    });

    // sent a message that we're good to proceed
    ctx.send("connection established.");
  });
}
```

Next we tie our setup function with our express server,
```javascript
// app.js or bin/www, where you currently have express setup

// app should be your express app
const server = http.createServer(app);

// pass the same server to our websocket setup function
// the websocket server will the run on the same port
// accepting ws:// connections
setupWebSocket(server);
```

Time to test, I use a firefox plugin called [Weasel](https://addons.mozilla.org/en-US/firefox/addon/websocket-weasel/) to connect to socket and test, there are similar alternatives in chrome.

Try connecting to the socket and also check the server logs to see the output of console.log statements. 
```
// connect to your express server host and port but using ws protocol
// for example
ws://localhost:3000
```

Let's add some more functionality to our server to check if individual client messages and broadcast messages are working fine.

Create the functions below in another file,

```javascript
// pipeline.js, for some examples

// client specific messages
// each client gets an individual instance
function individualPipeline(ctx) {
  let idx = 0;
  const interval = setInterval(() => {
    ctx.send(`ping pong ${idx}`);
    idx++;
  }, 5000);
  return interval;
}

// braodcast messages
// one instance for all clients
function broadcastPipeline(clients) {
  let idx = 0;
  const interval = setInterval(() => {
    for (let c of clients.values()) {
      c.send(`broadcast message ${idx}`);
    }
    idx++;
  }, 3000);
  return interval;
}
```

Import these functions in to our setup file,
```javascript
// setupWebSocket.js

function setupWebSocket(server) {
  // ws instance
  const wss = new WebSocket.Server({ noServer: true });

 // hookup broadcast pipeline
 broadcastPipeline(wss.clients);

 wss.on("connection", (ctx) => {
  /* ... */
  const interval = individualPipeline(ctx);
  /* ... */
  // clear the interval on connection close event
  ctx.on("close", () => {
   console.log("closed", wss.clients.size);
   clearInterval(interval);
  });
 }
```

Now use Weasel (or equivalent) and watch ping pong and broadcast messages. Connect from multiple tabs, and observe broadcast message appearing in sync in all tabs, while ping pong is specific to each client.
```
broadcast message 5
ping pong 0
broadcast message 4
```

I'll leave the link to client and server code on the final part as we are going to add more functionality to this.

We'll work on client side in Part-2.