Announcing Horizon 2: query aggregation, Auth0 integration, WebSockets

Today we’re pleased to announce the official release of Horizon 2.0, codenamed Mt. Whitney. You can install it today from npm.

Horizon 2.0 introduces a powerful new query aggregation feature, support for the Auth0 cloud service, several noteworthy architectural changes, and many bug fixes. The release represents the first round of improvements that we’ve implemented in collaboration with our user community since Horizon’s launch in May.

Aggregation queries

Query aggregation is the most significant new feature in version 2.0. The new aggregate and model functions provide a way to combine multiple Horizon queries, making it easy to track their collective output:

let hz = Horizon()
let aggregated = hz.aggregate({
  owner: hz("people").find("bob"),
  pet: hz("animals").find("spot"),
  related: {
    friends: hz("people").findAll({friendOf: "bob"}).limit(10),
    petFriends: hz("animals").findAll({friendOf: "spot"}).limit(10)
  },
  someConstant: "Always have this here",
})

You can invoke the aggregate function on a Horizon instance. Its parameter is an object that associates named properties with Horizon queries or other compatible values. You can chain a fetch or watch operation to the end of an aggregation, allowing you to either retrieve the values once or track the changes on an ongoing basis. When you watch an aggregation, it will emit updates any time one of the aggregated sub-queries has new results.

In addition to Horizon queries, aggregations can also include literal values, Observables, Promises, and arrays or objects that contain any of those supported values. Aggregations are powerful tools for composing multi-faceted queries.

You can also take advantage of various RxJS features to use Horizon aggregations for query orchestration and flow control. For example, the following code demonstrates how to use an Observable timer alongside a query in an aggregation to force the output to emit on the timed interval in addition to when the query receives an update:

hz.aggregate({
  counter: Observable.timer(0, 1000),
  someQuery: hz("foo").find("bar"),
}).watch().subscribe({ next(x){ console.log(x) }})

The model function is a convenience method that provides a shorthand for parameterizing aggregates, wrapping them in a callable function that lets you pass in arguments:

let myModel = hz.model((a, b, c) => ({
  foo: hz("foo").find(a),
  bar: hz("bar").find(b),
  baz: hz("baz").find(c)
});

var modelA = myModel(1, 2, 3);
var modelB = myModel(2, 3, 4);

You can optionally nest your models, which is often useful when you want to compose complex operations from smaller, reusable parts. For more details and more comprehensive examples, refer to the official documentation.

Auth0 integration

Auth0 is a popular identity management and single sign-on service. It’s available as an on-premise or hosted cloud platform that can handle authentication and user management for applications, with optional support for a selection of third-party OAuth providers.

You can use Auth0 with Horizon to enable conventional username/password authentication or to take advantage of their broader range of OAuth provider integrations. Horizon’s Auth0 support was contributed by community member Anton Poznyakovskiy.

Native WebSockets

We made some important changes to Horizon’s underlying network plumbing in version 2.0. The new version uses plain WebSockets for realtime messaging instead of engine.io. Given the ubiquity of native WebSocket support in browsers and other environments, many of you have indicated that you prefer the simplicity of a straightforward WebSocket-based protocol over the flexibility of engine.io’s transport-neutral abstraction layer.

Using vanilla WebSockets instead of engine.io simplifies some high-scalability deployment scenarios, particularly in cases where reverse proxies are involved. With the transition away from engine.io, Horizon no longer provides a built-in long-polling fallback. We are still evaluating possible avenues for making Horizon’s network transport layer extensible in the future.

Simplifying interoperability with RethinkDB

Horizon 2.0 includes a number of improvements that reduce friction for developers who want to build Horizon applications that interoperate with other RethinkDB applications or microservices.

When the Horizon backend creates the underlying RethinkDB table for a collection, the table and collection name are now consistent- -there’s no longer a random hash at the end of the table name. You can also insert data into the Horizon tables without manually adding a version field.

Horizon Roadmap

Horizon is still under heavy active development. In response to user feedback and lessons we learned from building our own applications with Horizon, we’re revisiting many of our early architectural decisions. You can expect to see a fair amount of churn in the coming months as we continue to overhaul key parts of the Horizon stack. Some of the coming changes may be disruptive, but they will result in a better developer experience as Horizon matures and becomes more suitable for adoption in production environments.

The 2.0 release addresses many of the most pressing concerns raised by Horizon early adopters. Our next big project is the design and implementation of a plugin system. Plugins will give users the ability to extend Horizon with additional features and capabilities. Additionally, the plugin system will make it easier for us to incorporate large features–like support for REST endpoints and adding custom Horizon commands–with less disruption to Horizon’s core.

We’re also exploring ways to make Horizon integrate more seamlessly with the rest of the Node.js ecosystem. In the long term, we aim to make Horizon more modular and easier to embed, while simultaneously taking better advantage of existing Node.js server and middleware frameworks. Those changes will have significant implications for how Horizon and applications that embed Horizon will handle authentication and other major parts of the developer experience.

We conduct all ongoing Horizon development in the open, with the direct involvement of our community. You can participate in the process and help shape the future of the Horizon stack. To learn more about our nascent plans for Horizon’s plugin system, you can follow the discussion on GitHub.

Conclusion

To see all of the features and improvements that we incorporated into the Horizon 2.0 release, check out the release milestone in our issue tracker on GitHub. For details about migrating your Horizon project from 1.x to 2.x, please refer to the compatibility notes in the Horizon 2.0 discussion thread. The Horizon command line tool includes a new hz migrate command to help you seamlessly transition your project to new versions of Horizon.

We’re especially grateful to the users who contributed to this release by providing feedback, feature recommendations, bug reports, and pull requests. Thank you for your support!