loading...

Websockets with React & Express [Part-1]

ksankar profile image Kailash Sankar Updated on ・3 min read

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

WebSocket server

We'll be using ws package to setup the websocket server. First let's write a websocket setup function.

// 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,

// 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 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,

// 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,

// 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.

Posted on by:

ksankar profile

Kailash Sankar

@ksankar

I'm a full stack web developer, jack of many and master of none.

Discussion

pic
Editor guide
 

For some reason the test connection in Weasel is not working for me. I keep getting "The Connection is Abruptly Closed or Couldn't be Opened ! CONNECTION CLOSED!" Does the URL and the protocol need to have WS in it? Or just the URL? Right now I have URL: ws://localhost:3001 and protocol: ws.

 

Protocol is optional, it's only needed if you are taking decisions on the server based on it's value.

Can you try connecting to wss://echo.websocket.org, it's an echo server and would return the messages posted to it. If this works, then the issue is on your localhost websocket server setup.
websocket.org/echo.html

 

Yeah, connecting to that URL works fine. I'll wait for the fifth article and compare my code to your's.

Maybe you can see something wrong. This is main file that kicks off the server. dev-to-uploads.s3.amazonaws.com/i/...

I didn't get it at first, but after staring at it for a while I think the reason is using
app.listen(port) instead of server.listen(port);
Never realised before but found a good post about it at StackOverflow

I still have some cleaning up to do on the code, here's what I've done till now on server

That was definitely the issue! Thank you so much!