Skip to content

MomenNano/fastify-websocket

 
 

Repository files navigation

fastify-websocket

js-standard-style CI workflow

WebSocket support for Fastify. Built upon ws.

Install

npm install fastify-websocket --save

Usage

There are two possible ways of using this plugin: with a global handler or with a per route handler.

Global handler

All you need to do is to add it to your project with register and pass handle function. You are done!

'use strict'

const fastify = require('fastify')()

fastify.register(require('fastify-websocket'), {
  handle,
  options: {
    maxPayload: 1048576, // we set the maximum allowed messages size to 1 MiB (1024 bytes * 1024 bytes)
    path: '/fastify', // we accept only connections matching this path e.g.: ws://localhost:3000/fastify
    verifyClient: function (info, next) {
      if (info.req.headers['x-fastify-header'] !== 'fastify is awesome !') {
        return next(false) // the connection is not allowed
      }
      next(true) // the connection is allowed
    }
  }
})

function handle (conn) {
  conn.pipe(conn) // creates an echo server
}

fastify.listen(3000, err => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

Per route handler

After registering this plugin, you can choose on which routes the WS server will respond. This could be achieved by adding websocket: true property to routeOptions on a fastify's .get route. In this case two arguments will be passed to the handler: socket connection and the original http.IncomingMessage (instead of the usual fastify's request and reply objects).

'use strict'

const fastify = Fastify()

fastify.register(require('fastify-websocket'))

fastify.get('/', { websocket: true }, (connection, req) => {
  connection.socket.on('message', message => {
    // message === 'hi from client'
    connection.socket.send('hi from server')
  })
})

fastify.listen(3000, err => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

In this case there won't be any global handler, so it will respond with a 404 error on every unregistered route, closing the incoming upgrade connection requests.

The route handler receives route params as a third argument:

fastify.get('/ws/:id', { websocket: true }, (connection, req, params) => {
  connection.write(`hi on stream ${params.id}`)
})

However you can still pass a default global handler, that will be used as default handler.

'use strict'

const fastify = require('fastify')()

function handle (conn) {
  conn.pipe(conn) // creates an echo server
}

fastify.register(require('fastify-websocket'), {
  handle,
  options: { maxPayload: 1048576 }
})

fastify.get('/', { websocket: true }, (connection, req) => {
  connection.socket.on('message', message => {
    // message === 'hi from client'
    connection.socket.send('hi from server')
  })
})

fastify.listen(3000, err => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

If you need to handle both HTTP requests and incoming socket connections on the same route, you can still do it using the full declaration syntax, adding a wsHandler property.

'use strict'

const fastify = require('fastify')()

function handle (conn) {
  conn.pipe(conn) // creates an echo server
}

fastify.register(require('fastify-websocket'), {
  handle,
  options: { maxPayload: 1048576 }
})

fastify.route({
  method: 'GET',
  url: '/hello',
  handler: (req, reply) => {
    // this will handle http requests
    reply.send({ hello: 'world' })
  },
  wsHandler: (conn, req) => {
    // this will handle websockets connections
    conn.setEncoding('utf8')
    conn.write('hello client')

    conn.once('data', chunk => {
      conn.end()
    })
  }
})

fastify.listen(3000, err => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

Options :

fastify-websocket accept the same options as ws :

  • objectMode - Send each chunk on its own, and do not try to pack them in a single websocket frame.
  • host - The hostname where to bind the server.
  • port - The port where to bind the server.
  • backlog - The maximum length of the queue of pending connections.
  • server - A pre-created Node.js HTTP/S server.
  • verifyClient - A function which can be used to validate incoming connections.
  • handleProtocols - A function which can be used to handle the WebSocket subprotocols.
  • path - Accept only connections matching this path.
  • noServer - Enable no server mode.
  • clientTracking - Specifies whether or not to track clients.
  • perMessageDeflate - Enable/disable permessage-deflate.
  • maxPayload - The maximum allowed message size in bytes.

For more informations you can check ws options documentation.

NB: By default if you do not provide a server option fastify-websocket will bind your websocket server instance to the scoped fastify instance.

Acknowledgements

This project is kindly sponsored by nearForm.

License

Licensed under MIT.

About

basic websocket support for fastify

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 93.6%
  • TypeScript 6.4%