forio Toggle navigation

How To: Compare Epicenter APIs

A big part of the work in creating a project is making sure that your user interface and your model are connected: user inputs are written to model variables, model variables are displayed and updated in the interface, and operations (functions or methods) in the model are called from the interface at appropriate times.

Epicenter provides several different APIs, at different levels of abstraction, so you can choose which interfaces make the most sense for you and your project.

This example compares sample code written at different levels of the Epicenter stack (Flow.js, Epicenter.js API Adapters, RESTful APIs) to help you make this choice.

Epicenter Architecture Diagram
Jump to sample code using:

Model Code

For our example, let's start with a very simple model. This one is in Python, but you could write something similar in any of our supported modeling languages.

# in model.py
from epicenter import Epicenter

revenue = 0
cost = 0
profit = 0

def calculate_profit():
    global revenue, cost, profit

    profit = revenue - cost

    Epicenter.record('profit', profit)

    return profit

Our model has three variables, only one of which is persisted, and one operation.

Run API

The Run API is a RESTful API that collects common tasks around creating and updating runs, variables, and data in one endpoint. In this example, we're calling it using JavaScript (and jQuery).

Read more about the Run API.

For this sample project, we want an interface that allows end users to enter revenue and cost, call the operation to calculate profit, and view the calculated profit.

Note that our Team ID is "acme-simulations" and our Project ID is "demo".

<!doctype html>
<html>
    <head>

        <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>

        <style>
            body { font-family: arial; font-size: 18px; }
            label { display: block; margin-top: 20px; }
            div { min-height: 1.5em; }
        </style>

    </head>
    <body>

        <label for="revenue">Revenue</label> <input id="revenue">
        <label for="cost">Cost</label> <input id="cost"><br>
        <label>Profit</label> <div id="profit"></div>

        <button id="calc">Calculate</button>
        <button id="reset">Reset</button>

        <script>
            var runId = '';
            var apiUrl = 'https://api.forio.com/run/acme-simulations/demo/';

            var initializeRun = function () {
                return $.ajax({
                    type: 'POST',
                    url: apiUrl,
                    contentType: 'application/json',
                    data: JSON.stringify({
                        model: 'model.py'
                    })
                })
                .then(function (run) {
                    runId = run.id;
                });
            };

            var showResults = function () {
                $.ajax({
                    type: 'GET',
                    contentType: 'application/json',
                    url: apiUrl + runId + '/variables?include=profit',
                })
                .then(function (resp) {
                    $('#profit').text(resp.profit);
                });
            };

            // when an input changes
            $('#revenue, #cost').on('change', function () {
                var revenue = +$('#revenue').val() || 0;
                var cost = +$('#cost').val() || 0;

                $.ajax({
                    type: 'PATCH',
                    contentType: 'application/json',
                    url: apiUrl + runId + '/variables',
                    data: JSON.stringify({
                        revenue: revenue,
                        cost: cost
                    })
                });

            });

            // when the Calculate button is pressed
            $('#calc').on('click', function () {
                $.ajax({
                    type: 'POST',
                    url: apiUrl + runId + '/operations/calculate_profit',
                })
                .then(showResults);
            });

            $("#reset").on('click', function () {
                initializeRun().then(function () {
                    $('input').val('');
                    $('#profit').text('');
                });
            });

            // start by initializing the model & run
            initializeRun();

        </script>
    </body>
</html>


API Adapters: Epicenter.js

The API Adapters (Epicenter.js) abstract the underlying RESTful APIs, including the Run API, into a set of services and utilities, so you can write directly in JavaScript. You can use this library with either callbacks or promises; in this example, we're using promises.

Read more about Epicenter.js.

For this sample project, we want an interface that allows end users to enter revenue and cost, call the operation to calculate profit, and view the calculated profit.

Note that our Team ID is "acme-simulations" and our Project ID is "demo".

<!doctype html>
<html>
    <head>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
        <script src="//forio.com/tools/js-libs/2.1.0/epicenter.min.js"></script>            
        <style>
            body { font-family: arial; font-size: 18px; }
            label { display: block; margin-top: 20px; }
            div { min-height: 1.5em; }
        </style>
    </head>
    <body>

        <label for="revenue">Revenue</label>
            <input id="revenue" type="text">

        <label for="cost">Cost</label>
            <input id="cost" type="text">

        <label>Profit</label><div id="profit"></div>

        <button id="calc">Calculate</button>
        <button id="reset">Reset</button>

        <script>
            var runManager = new F.manager.RunManager({
                run: {
                    account: 'acme-simulations',
                    project: 'demo',
                    model: 'model.py',
                    server: {
                        host: '//api.forio.com'
                    }
                }
            });

            runManager.getRun().then(function () {

                $('#revenue, #cost').on('change', function () {
                    var revenue = +$('#revenue').val() || 0;
                    var cost = +$('#cost').val() || 0;

                    runManager.run.variables().save({
                        revenue: revenue,
                        cost: cost
                    });
                });


                $('#calc').on('click', function () {
                    runManager.run.do('calculate_profit').then(function () {
                        runManager.run.variables()
                            .query({ include: ['profit'] })
                            .then(function (resp) {
                                $('#profit').text(resp.profit);
                            });
                    });
                });

                $("#reset").on('click', function () {
                    runManager.reset().then(function () {
                        $('input').val('');
                        $('#profit').text('');
                    });
                });
            });

        </script>
    </body>
</html>


Flow.js

Flow.js provides bindings between HTML elements in your user interface and variables and methods in your project's model.

The Interface Builder generates code using Flow.js. If you initially use the Interface Builder to create your interface, you can easily edit or add to this generated code once you have a little familiarity with Flow.js.

Read more about Flow.js.

For this sample project, we want an interface that allows end users to enter revenue and cost, call the operation to calculate profit, and view the calculated profit.

Note that our Team ID is "acme-simulations" and our Project ID is "demo".

<!doctype html>
<html>
    <head>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
        <script src="//forio.com/tools/js-libs/2.1.0/epicenter.min.js"></script>
        <script src="//forio.com/tools/js-libs/flow/latest/flow.min.js"></script>

        <style>
            body { font-family: arial; font-size: 18px; }
            label { display: block; margin-top: 20px; }
            div { min-height: 1.5em; }
        </style>

    </head>
    <body data-f-convert=" $#,###.00">

        <label for="revenue">Revenue</label>
            <input data-f-bind="revenue" type="text">

        <label for="cost">Cost</label>
            <input data-f-bind="cost" type="text">

        <label>Profit</label><div data-f-bind="profit"></div>

        <button data-f-on-click="calculate_profit">Calculate</button>
        <button data-f-on-click="reset">Reset</button>

        <script>
            Flow.initialize({
                channel: {
                    strategy: 'new-if-persisted',
                    run: {
                        account: 'acme-simulations',
                        project: 'demo',
                        model: 'model.py',
                        server: {
                            host: 'api.forio.com'
                        }
                    }
                }
            });
        </script>
    </body>
</html>