fortune

A library for managing data in Node.js and web browsers.

Fortune.js is a library for managing data in Node.js and web browsers. It segregates data access, business logic, and external I/O, providing a baseline for interoperability and allowing each implementation to be swapped interchangeably.

View the website for documentation. Get it from npm:

$ npm install fortune --save

Fortune.js has a minimal public interface, mostly just the constructor and request method. Calling request dispatches calls to three extensible interfaces that work together: Adapter, Serializer, and transform functions, based on the request data.

  • The Adapter abstraction allows for multiple persistence back-ends, such as common server-side databases like Postgres and MongoDB, and IndexedDB in the web browser.
  • Optional: The Serializer abstraction allows for multiple I/O formats, including media types such as Micro API and JSON API, standard input formats such as URL encoded and form data, and custom serializers for HTML.
  • Optional: Transform functions isolate business logic, so that it may stay consistent no matter what adapter, serializer, or network protocol is used.

Included are networking wrappers which call the request method, so it is not coupled with any external protocol, and it should be able to work with any transport layer such as HTTP and WebSocket.

The only necessary input is record type definitions. Here's a model of a basic micro-blogging service:

const fortune = require('fortune')
 
const store = fortune({
  user: {
    name: { type: String },
 
    // Following and followers are inversely related (many-to-many). 
    following: { link: 'user', inverse: 'followers', isArray: true },
    followers: { link: 'user', inverse: 'following', isArray: true },
 
    // Many-to-one relationship of user posts to post author. 
    posts: { link: 'post', inverse: 'author', isArray: true }
  },
  post: {
    message: { type: String },
 
    // One-to-many relationship of post author to user posts. 
    author: { link: 'user', inverse: 'posts' }
  }
})

By default, the data is persisted in memory. There are adapters for databases such as MongoDB, Postgres, and NeDB. To make a request internally:

store.request({
  type: 'user',
  method: 'create',
  payload: [ { name: 'John Doe' }, { name: 'Jane Doe' } ]
})

The first call to request will trigger a connection to the data store, and it returns the result as a Promise.

Then let's add a HTTP server:

const http = require('http')
 
// The `fortune.net.http` helper function returns a listener function which 
// does content negotiation, and maps the internal response to a HTTP response. 
const server = http.createServer(fortune.net.http(store))
 
store.connect().then(() => server.listen(1337))

This yields an ad hoc JSON over HTTP API. There are serializers for Micro API (JSON-LD) and JSON API, which also accept HTTP parameters. In addition, Fortune.js implements a wire protocol based on WebSocket and MessagePack.

See the plugins page for more details.

  • Type validations, with support for custom types.
  • Application-level denormalized inverse relationships.
  • Dereferencing relationships in a single request.
  • Isomorphic, backed by IndexedDB in web browsers, including a built-in wire protocol for data synchronization.
  • No active record pattern, just plain data objects.
  • No coupling with network protocol.

Fortune.js is written in ECMAScript 5.1 syntax, with some ECMAScript 6 additions.

  • Promise (ES6): not supported in IE, supported in Edge.
  • WeakMap (ES6): supported in IE11+, Edge.

This software is licensed under the MIT license.