DEV Community

Cover image for Build a Serverless WebSocket Application in 5 minutes with Lolo
Lolo Code
Lolo Code

Posted on

Build a Serverless WebSocket Application in 5 minutes with Lolo

Originally published here.

WebSockets are mainly used to create real-time applications, such as chat apps, collaboration platforms and streaming dashboards. These applications take advantage of two-way/bidirectional communication between a server and users’ browsers.

Serverless is usually associated with FaaS, an isolated stateless function that is triggered by another service. Creating a Serverless Websocket application would require you to use AWS Lambda with WebSockets in API Gateway and DynamoDB to store connections. This is overly complicated.

We’ll show you how to create something faster. Serverless iFaaS platforms don’t require initialization before the function executes so you don’t pay a price for waking up a container once it has been deployed. It’s technically always live. You also have access to a baked in key / value store which means that you don’t end up loosing state between subsequent invocations. I.e. you don’t have to start from a blank slate on every invocation. Hence the lack of need for an external database such as DynamoDB.

The Plan

We’ll demonstrate something very simple here by using a pre-made Websocket Trigger to connect and broadcast all messages to all connected clients. See the visual workflow below. You’ll need a free Lolo account to set this up yourself.

Image description

If you want to get started right away you can simply copy the contents of this document and paste it into a new application in a blank graph in Lolo. Save and Run the application to deploy it. That’s 1 minute of work.

Do follow along though if you want to understand how to use it or if you want to set this up from scratch.

Create an Application and add a Trigger

To begin, we need to set up a new WebSocket server that can handle inbound WebSocket requests from clients.

We do this by first creating a new application in your Lolo account and then adding the Lolo/Websocket Trigger from the Functions Gallery on the left of the graph. Add in a path name, such as /socket. You can also rename it.

Image description

Process the Incoming Request

When you add this WebSocket Trigger you get three output ports in the node called req, message and close so you need to setup ways to process these requests. Add another inline Function (i.e. a custom function) and name it ‘Process Request.’ Remove the in port and instead add in three in ports called req, msg and close.

Link the ports to the right in and out ports with the nodes, look below for an illustration on how to do this.

Image description

We need a bit of code to do something here with the WebSocket connection. Copy and paste in the code from below. Open up the Process Request node and paste in the code below in the handler.

const connections = {};

exports.handler = async (ev, ctx) => {
  const { route, input, inputs, log, emit } = ctx;
  const { sessionId } = ev;

  // check incoming port (i.e. req, message or close)
  switch (input) {

    // on first connection
    case inputs.req:
      connections[sessionId] = {
        send: body => emit('response', { body }),
        end: () => emit('response', { end: true }),
        info: ev.headers
      }
      ev.body = { connected: true, yourConnectionId: sessionId };
      // re-route data to 'req' output port
      route(ev, 'req');
      break;

    // on subsequent messages 
    case inputs.msg:
      // re-route data to 'msg' output port
      route({ connections, message: ev.message, sessionId }, 'msg')
      break;

    // when client disconnects 
    case inputs.close:
      log.info("client has disconnected");
      delete connections[sessionId];
      break;
  }
};

Enter fullscreen mode Exit fullscreen mode

The code above is checking what ports the incoming data is routed through, giving us a way to handle a new connection by adding it to connections. We are also setting up how we want to handle subsequent messages and a disconnecting client by using the in ports, msg and close.

This code above though is re-routing to other nodes via the route() method as well. As you can see we have two output routes here to ‘req’ and ‘msg.’ We thus need to add those two output ports as well.

Image description

Send back a response

Now we have two outports in the Process Request Function that needs to go somewhere, so we create another inline Function called Affirm Connection and paste in the code below.

All this does is signal the listener within the WebSocket Trigger to send a response to the client. We will route the req route to this node.

exports.handler = async(ev, ctx) => {
  const { emit, log } = ctx;
  // Log to the console that a client has connected
  log.info("client has connected");
  // send response to the client
  emit('response', ev);
};
Enter fullscreen mode Exit fullscreen mode

Along with this we also need a way to handle subsequent messages. In this case we said we would broadcast all messages to all clients when someone sends something. So, create another inline Function (i.e. a custom function) and call it Handle Messages. Paste in the code below, see comments to understand what it does.

exports.handler = async (ev, ctx) => {
  // extract connections, and current session id from the event data
  const { connections, sessionId } = ev;
  // send messages
  await broadcastToAll(ctx, connections, sessionId, ev);
};

const broadcastToAll = async ({ log }, connections, currentSessionId, ev) => {

  // loop through connections
  Object.keys(connections).forEach(sessionId => {
    try {
        // send message to everyone but the current sessionId
        if (currentSessionId !== sessionId) {
        connections[sessionId].send(`${sessionId} says: ${ev.message}`)
        } 
    } catch (e) {
      log.error(e)
    }
  })

};
Enter fullscreen mode Exit fullscreen mode

You can remove the out ports for both of these new Functions. Now we also have to route the data visually from the Process Request node to the other two nodes we’ve created.

See these steps in action below.

Image description

Save and Deploy

Alright, that was it. You can save and deploy.

Look in the Logs for the ‘Listening to port 4000’ message to see if it is ready to use. This may take awhile. We are not using any NPM modules here so should be faster but if we did we would have to wait about a minute.

Now go into the WebSocket Trigger to collect the External URL. We are going to use it to connect to this Websocket.

Open two terminals on your computer and then connect via wscat.

wscat -c wss://eu-1.lolo.co/:appId/socket
Enter fullscreen mode Exit fullscreen mode

Remember to NPM install wscat -g (via your terminal) first if you don’t already have wscat installed.

Now you should be able to talk via the different terminals. You can ask a friend to connect on a different computer and talk that way.

It goes without saying that you can connect this via a frontend to build a quick chat app.

Image description

Remember if you are having issues, just copy the contents of this document and paste it into an empty graph in a Lolo application to get the entire app set up for you.

Let us know if you have any feedback. We’re keen to create a better Serverless experience.

Top comments (0)