Real-Time WebSocket Connections for Node.js with ws-low-level
Tags: webdev, javascript, programming, tutorial
Published: 2024-05-26 14:42:18



Achieving real-time connections is easy using WebSockets. Though you may opt for long polling to update a client statelessly, the ability to handle and manage a stateful WebSocket connection makes it possible to work in real-time communications with the client.

WebSocket is a bi-directional data messaging protocol. The connection begins as an HTTP call, which initiates a handshake to work through the details of the connection. Once the connection is established, the client and server can send messages to each other. Messages are formatted as UTF-8 text or binary.

With the Node 22 update, the WebSocket client is now available in Node, so you can build server-to-server WebSocket connections with Node.js as the client.

Clearly WebSockets have a lot of value, so let's build a server!

## Achieving Real-Time Connections with Node.js

In this article I'm going to show you how to get started with creating a WebSocket server for Node.js using the npm library ws-low-level. ws-low-level provides the API to receive and send messages, and handle the WebSocket handshake. 

As its name suggests, ws-low-level is *low-level*, in the sense that it gives you access to the raw parts of the WebSocket protocol. With this access comes the trade-off of more control versus more verbosity. And ws-low-level is indeed verbose -- the example in the README file for the [ws-low-level repo](https://www.npmjs.com/package/ws-low-level) is over 150 lines of code!

That is not to say ws-low-level is overly complex, however. The example from the README file is simple enough. 

And the ws-low-level API is actually providing you with a robust, Promise-based, standard-compliant WebSocket server. Because it is low-level, you will have the opportunity, once your server is in development, to add to it and customize it the way that you want.

### Getting Started

I will walk you through setting up a WebSocket server using ws-low-level. 

First, make sure you have the correct prerequisites installed. You will need Node.js, which you can get from the [Node download page](https://nodejs.org/en/download). This will also install npm. You can check your installation by running `node --version` and `npm --version`.

Let me explain how ws-low-level works with Node.js.

ws-low-level ties in to the standard library of Node.js. In Node.js, the WebSocket HTTP upgrade is available through Node's `http` package with the `'upgrade'` event handler. A request to establish a WebSocket will trigger this event. Below is an example server that uses the event and logs the word "upgrade" to the console whenever a WebSocket connection is requested.

```javascript
import http from 'http';

const httpServer = http.createServer(
    function (
        request /* <http.IncomingMessage> */,
        response /* <http.ServerResponse> */
    ) {
        // Handle HTTP messages by verbs like GET and POST
    }
);

httpServer.on('upgrade', function (
    request /* <http.IncomingMessage> */,
    socket /* <stream.Duplex> */,
    head /* <Buffer> websocket header */
) {
    // Handle a WebSocket connection
    console.log('upgrade');
});

httpServer.listen(3000);
```

The above code shows how to use Node.js to handle a WebSocket. Note that Node.js does not handle the WebSocket handshake, nor parse incoming WebSocket frames, nor prepare outgoing messages as WebSocket frames. We need a third-party library to help get started with our WebSocket server. 

### Using ws-low-level

Enter ws-low-level! ws-low-level is a third-party library available on npm for handling Node.js WebSocket connections. To install the library, enter in your terminal:

```bash
npm install ws-low-level
```

Now, back to our server, we can import from ws-low-level all of the imports that we will need. I recommend importing all five of the following imports, because you will eventually need them all.

```javascript
import {
    sendHandshake,
    getMessagesFactory,
    sendFactory,
    prepareWebsocketFrame,
    prepareCloseFramePayload
} from 'ws-low-level';
```

Now we can add a WebSocket handshake to the web server, and the connection will be established. Let's modify the callback for the `'upgrade'` event to include `sendHandshake`.

```javascript
httpServer.on('upgrade', function (
    request /* <http.IncomingMessage> */,
    socket /* <stream.Duplex> */ ,
    head /* <Buffer> websocket header */
) {
    sendHandshake(
        request,
        socket
    );
});
```

The above code will complete the WebSocket handshake, establishing a WebSocket connection. (That was simple!)

### Next Steps

Now that we have a connection established, it should be clear what we need to do next -- we need to handle receiving and sending messages. To continue on your journey, I recommend you proceed to the example server on [ws-low-level's README](https://www.npmjs.com/package/ws-low-level). It should be clear how to use the send and receive functionalities.

This has been a brief introduction to real-time WebSocket communication for Node.js using ws-low-level. As the creator of ws-low-level, I'd like to say thank you for reading!