forio Toggle navigation

Epicenter.js: API Adapters

The Epicenter API Adapters are part of the epicenter.js library. This library abstracts the underlying Epicenter RESTful APIs into a set of services and utilities.

If you are comfortable with JavaScript, the epicenter.js library is an easy way to connect your project's model, data, and user interface.

The current version of Epicenter.js is 2.0. See the Including section below. You can also view the history of releases on GitHub.

Concepts in Epicenter.js

The Epicenter.js library is a set of services (adapters) and managers to help streamline your work with the underlying Epicenter APIs.

Services encapsulate the Epicenter REST APIs. Managers are responsible for configuring, sequencing, and synchronizing services to perform common application tasks. For example, the Run Manager lets you use different run creation strategies and returns a pre-configured Run Service you can then use.

In most cases you'll work with the managers directly:

  • Authorization Manager: The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.
  • Run Manager: The Run Manager gives you control over run creation depending on run state. You can select run creation strategies (rules) for which runs end users of your project work with when they log in to your project.
  • World Manager: For building multiplayer games you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create "worlds" to handle such cases. The World Manager provides an easy way to track and access the current world and run for particular end users.
  • Epicenter Channel Manager (and the underlying Channel Manager): Once you've created "worlds" with the World Manager, you often want end users in each world to be able to communicate: to talk with each other (e.g. a user-to-user chat feature), or to receive updates when something changes in their world (e.g. variables associated with their shared run are updated). The Epicenter Channel Manager provides a publish/subscribe channel using cometd.

Although in most cases you'll work with the managers directly, the services are also available if you just want to communicate with the underlying RESTful APIs:

Using Epicenter.js

Including

Epicenter.js

The Epicenter.js library is available from our tools: https://forio.com/tools/js-libs/2.0.12.0.1/epicenter.min.js. To use it in your project, simply add

<script src="//forio.com/tools/js-libs/2.0.1/epicenter.min.js"></script>

into any of your interface files (e.g. .html and .js files).

Dependencies

The Epicenter.js library depends on jQuery, so you'll also need to download jQuery for yourself, or use a hosted version. To use a hosted version, add

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

Extensions

If you are building a multiplayer game, you'll also need to include the epicenter-multiplayer-dependencies.js library. This is available from our tools: https://forio.com/tools/js-libs/2.0.1/epicenter-multiplayer-dependencies.js. To use it in your project, simply add

<script src="//forio.com/tools/js-libs/2.0.1/epicenter-multiplayer-dependencies.js"></script>

into any of your interface files (e.g. .html and .js files).

Provided Components

In addition to the Epicenter.js library itself, the Epicenter JS Libs project also includes reusable components. These HTML, CSS, and JS files are templates you can use to perform common actions. They can be copied directly to your project, often without modification.

Login Component

Provides a login form for team members and end users of your project. Includes a group selector for end users that are members of multiple groups.

  • index.html: The login form.
  • login.css: Provides styling for the group selector pop over dialog.
  • login.js: Uses the Authorization Manager to log in users.

The login component is available from GitHub.

Assignment Component

Provides an interface to automatically assign end users to worlds, for multiplayer projects. Includes the ability to set the number of end users per world, assign and unassign end users, and mark certain end users as inactive (e.g. if they are not present on the day the simulation game play is occurring). These features are all available within the Epicenter interface (see Multiplayer Settings and Multiplayer Assignment); this component allows you to easily add them to your project. For example, this way a facilitator could make the end user assignments to worlds in your project's user interface, without needing to log in to Epicenter directly.

  • index.html: The form for automatic end user assignment to worlds.
  • assignment.css: Styles and icons used in the form.
  • assignment.js: Uses the World API Adapter to assign end users to worlds.

The assignment component is available from GitHub.

Accessing

Within your interface file, each service can be accessed using the F namespace.

For example:

var rm = new F.service.RunManager();

Examples of Usage: Callbacks and Promises

There are two different patterns for using the service adapters: using callbacks or using promises.

Callbacks

All services take in an "options" configuration object as the final parameter. Among other things, the options object contains the following properties:

  • success: Called when the call completes successfully
  • error: Called when the call fails
  • complete: Called when the the call completes, regardless of success or failure
  • progress: Called at any significant point in the progress of the call, usually before and after server requests

For example, you might write a sequence of operations using callbacks:

var rm = new F.service.RunManager({
    run: {
        account: 'myTeamId',
        project: 'sales_forecaster',
        model: 'sales_forecaster.jl'
    }
});
rm.getRun({
    success: function() {
        rm.getRun(function(run) {
            run.serial(
                ['initialize_inputs', 'calculate_input_totals', 'forecast_monthly_profit'], 
                null, 
                { success: function(data) {
                    displayUI(data, function () {
                        hideLoadingScreen(function () {
                            run.variables().load('profit_histogram');
                        });
                    });
                  },
                  error: function() {
                    console.log('Oops! Something went wrong with the operations');
                  }
                }
            )
        });
    }
});

Callbacks work well for one-off operations, but can become difficult to follow when used for a longer sequence of steps.

Promises

Every service call returns a promise. All services support the jQuery Deferred Object functions, including the following most common functions:

  • then: Add handlers to be called when the object is resolved, rejected, or still in progress
  • done: Add handlers to be called when the object is resolved
  • fail: Add handlers to be called when the object is rejected

For example, you might write the same sequence of operations as above using promises:

var rm = new F.service.RunManager({
    run: {
        account: 'myTeamId',
        project: 'sales_forecaster',
        model: 'sales_forecaster.jl'
    }
});
rm.getRun()
    .then(function(run) {
        run.serial(['initialize_inputs', 'calculate_input_totals', 'forecast_monthly_profit'])
            .then(displayUI)
            .then(hideLoadingScreen)
            .then(function () {
                run.variables().load('profit_histogram');
            })
            .fail(function() {
                console.log('Oops! Something went wrong with the operations');
            });
    });

See for example this blog for more background on how promises work in JavaScript.

Configuration Options

Every service takes in a configuration options object as the last parameter. This optional parameter allows you to override any of the default configuration options.

Default configuration options are described for each service on the service reference page. You can override them when you create a service object, and again whenever you make a call.