Announcing Faye 1.0

It’s been over four years in the making, but I’m very happy to announce the release of Faye 1.0. The Faye project – both the pub/sub messaging tools and the WebSocket/Redis modules that have been extracted over time – have reached a level of stability where I think it’s grown out of the ‘beta’ 0.x phase of development. Judging by the volume of bug reports and questions I get, the codebase has settled into something stable, usable, and free of commonly encountered faults.

The 1.0 release does not introduce many new major features, but rather builds on the stability of the 0.8 release and adds some much-needed polish in a few areas. Let’s start with the big changes you need to be aware of.

First, several methods have been removed. The most significant of these is the server’s listen() method. This was really just a little sugar over starting an HTTP/HTTPS server and attaching Faye to it, and over time the amount of different options people needed, from configuring the SSL cipher suite to picking a different Ruby webserver, indicates this one method should not try and cover all use cases. Instead, users should set up their HTTP server as they want, and bind Faye to it. The documentation covers how to do this.

On the client side, getClientId() and getState() have been removed. They were only ever there to support tests, they were never documented, and I have constantly discouraged their use. If you’re going to miss them and don’t know how to adapt your application, please ask the mailing list.

At the protocol level, the server no longer forwards the clientId field of messages to subscribers. I have discouraged use of this value as a security credential, and it was never intended as such, but to remove the risk for people who are using it this way I have made sure it does not get shared between clients.

Those are all the breaking changes. There’s a few places where existing APIs still work but have been augmented with modern equivalents.

Objects that represent publication/subscription and respond to the callback()/errback() API are now Promises, and callback/errback are internally implemented on top of then(). This is a spec-compatible promise implementation and should interoperate with any other promise library you’re using.

Objects like the server/adapter that respond to bind() for handling events now implement the EventEmitter API. bind() still works, it’s just sugar for on()/addListener().

Elsewhere there is plenty of polish and modernisation. At the transport level, custom header support has been added to the cross-origin-long-polling and server-side websocket transports. When using a client outside the browser, all transports now support cookies and share a cookie jar scoped to the client. The transports have all been refactored and are now more reliable at detecting and recovering from network errors and from client devices/applications going to sleep.

In the Client class, we’ve added a ca option to the constructor; like elsewhere in the core Node APIs this lets you pass in an array of trusted server certificates if you need to go beyond the certificates trusted by OpenSSL. Clients can also be instantiated with URI objects (from Node’s url.parse() or Ruby’s URI.parse()) instead of URL strings, and they are treated as objects in all internal URL-handling code. You can also use protocol-relative URIs in the browser, no problem.

In Ruby, some major changes mean that we now support JRuby. For example, Yajl has been replaced with MultiJson so you can choose the JSON engine that’s right for your project. And you no longer need to use Thin; Faye::RackAdapter supports the rack.hijack streaming API supported by Puma, Rainbows 4.5 and Passenger 4.0, so you have more choices for which server to use (this was a major motivator for the removal of the Thin-specific listen() method).

Beyond all these little bits of polish, we come to the one real new feature of 1.0. Until now, Faye has not let you access HTTP request data in server-side extensions, since the aim was to hide all the messy transport details. But over the years it’s become apparent some people want to use various HTTP auth mechanisms and other features in their extensions, so Faye 1.0 makes this available with the caveat that usage is at your own risk. For certain HTTP features, you must read the updated security docs, particularly the material on CSRF protection.

In short, if your extension methods have 3 parameters, the second one will now be a request object (http.Request on Node, Rack::Request on Ruby). This gives you access to the path, headers and body of the request, which you can use to filter messages.

server.addExtension({
  incoming: function(message, request, callback) {
    if (request.headers.authorization !== 'open sesame') {
      message.error = '403::Access denied';
    }
    callback(message);
  }
});

2-parameter extensions still work exactly the same as they always did.

That just about covers the main changes in the 1.0 release. As always, file bugs on GitHub and ask questions on the mailing list.

On a personal note, I want to thank everyone who has built stuff, asked questions, reported bugs, fixed code, and donated their time to this project. It has been and continues to be really rewarding to work on, and has taken me all over the place talking at confs and meeting people who want to hear about it. It was particularly gratifying to see Faye powering the GOV.UK exhibit at the 2013 Design Awards, at one of my favourite London museums. I’m proud to have helped a lot of projects build on my work but there’s nothing quite like seeing something you helped build in the real world, especially somewhere as dear to me as the Design Museum.

Thank you, and I hope you keeping putting Faye to good use.