Vercel makes it easy to deploy and scale HTTP APIs using Serverless Functions. However, it’s not possible to use serverless functions to host WebSocket APIs. Does this mean you need to give up on your hopes and dreams and set up normal servers to handle your WebSockets? No way! Vercel can be combined with Fanout Cloud to handle WebSocket connections without having to literally host them.

fanout-vercel

By using Vercel and Fanout Cloud together, API logic can be kept in one place. Fanout Cloud can manage the WebSocket connections, and invoke functions whenever there is client activity. What’s great about this approach is there’s nothing extra to deploy, and it works at high scale too.

Example

Below is some code for a simple WebSocket chat API. Messages received from clients are broadcasted to all other connected clients. It uses the serve-grip library, which provides a pseudo-WebSocket connection object. “GRIP” is the name of the integration protocol Fanout uses with the backend server.

const { ServeGrip } = require( '@fanoutio/serve-grip' );
const { WebSocketMessageFormat } = require( '@fanoutio/grip' );

const serveGrip = new ServeGrip({grip: process.env.GRIP_URL});

module.exports = async (req, res) => {

    await serveGrip.run(req, res);

    const { wsContext } = req.grip;
    if (wsContext == null) {
        res.statusCode = 400;
        res.end('Not a WebSocket-over-HTTP request\n');
        return;
    }

    // if this is a new connection, accept it and subscribe it to a channel
    if (wsContext.isOpening()) {
        wsContext.accept();
        wsContext.subscribe('all');
    }

    while (wsContext.canRecv()) {
        const message = wsContext.recv();

        if (message == null) {
            // if return value is undefined then connection is closed
            wsContext.close();
            break;
        }

        // broadcast to other connections
        const publisher = serveGrip.getPublisher();
        await publisher.publishFormats(
            'all',
            new WebSocketMessageFormat(message)
        );
    }

    res.end();
};

For demonstration purposes, the above code has been deployed and set up as follows:

  • The code has been deployed to Vercel with base URL https://vercel-websocket.vercel.app.
  • The Fanout domain bce4b2a0.fanoutcdn.com has been set up with vercel-websocket.vercel.app:443 as its origin server.
  • The GRIP_URL environment variable has been set on the Vercel app, containing Fanout credentials.

It is possible to connect with a WebSocket client and send a message:

$ wscat -c wss://bce4b2a0.fanoutcdn.com/api/chat
connected (press CTRL+C to quit)
> hi
< hi

How it works

Fanout Cloud acts as a proxy between clients and an origin server, with some important abilities:

  • WebSocket client traffic is converted into a series of HTTP requests sent to the origin server. This makes it possible for a plain HTTP backend to react to WebSocket traffic.
  • The origin server can associate publish-subscribe channels with client connections, and then publish raw WebSocket messages to be injected into those client connections.

The serve-grip library provides a socket-like object called WebSocketContext that handles the event marshalling over HTTP. The object contains methods like accept(), send(), recv(), etc. What’s interesting is that these methods don’t operate directly on a real WebSocket. When recv() is called, it simply iterates over the events received in the current HTTP request. When send() is called, events are temporarily enqueued and a middleware serializes them at the end into the HTTP response. WebSocketContext objects are not long-lived, and a fresh one is created for each handler invocation and destroyed afterwards.

The library also provides ways to subscribe connections to channels as well as to publish to channels. Notably, clients have no awareness of GRIP or channels. They just connect to WebSocket URLs and exchange arbitrary messages, the meaning of which is determined by your application.

For protocol details, see Generic Realtime Intermediary Protocol and WebSocket-over-HTTP.

Serverless WebSockets, today

Sign up for a free Fanout Cloud account and get a WebSocket API up and running in no time.