External Web Clients

You may want to build your own custom web applications using Girder. Since Girder cleanly separates API from UI, it is straightforward to use a mounted Girder API for app authentication and data storage. You may additionally use Girder’s JavaScript libraries and UI templates to assist in building applications.

Including the Girder REST API

Apache

See the Deployment Alternatives section for instructions on deployment of Girder under Apache. You may host your web application alongside Girder and use its REST interface.

Tangelo

Tangelo is a CherryPy based web server framework for rapid data analytics and visualization application development. Tangelo has options for directly mounting the Girder API and static application files inside a Tangelo instance. See details in Tangelo’s setup documentation.

Using Girder JavaScript Utilities and Views

Including the JavaScript

All Girder code is packaged within ES6 modules, and may be directly included in other web applications via imports. The Webpack tool is recommended as a way to resolve imports and build deployable applications.

Extending Girder’s Backbone application

Girder defines a main application class, App. This object is responsible for bootstrapping the application, setting up the overall layout, and responding to global events like g:login and g:navigateTo. Developers can choose to derive their own application from this class to use the functionality that it provides. For example, the following derivation would modify the normal application bootstrapping

import Backbone from 'backbone';

import { setCurrentUser } from '@girder/core/auth';
import UserModel from '@girder/core/models/UserModel';
import { setApiRoot } from '@girder/core/rest';
import router from '@girder/core/router';
import eventStream from '@girder/core/utilities/EventStream';
import App from '@girder/core/views/App';

// set the path where girder's API is mounted
setApiRoot('/girder/api/v1');

var MyApp = App.extend({
    start: function () {
        // disable girder's router
        router.enabled(false);

        // call the super method
        return App.prototype.start.call(this, {
            fetch: false,   // disable automatic fetching of the user model
            history: false, // disable initialization of Backbone's router
            render: false   // disable automatic rendering on start
        }).done(() => {
            // set the current user somehow
            setCurrentUser(new UserModel({...}));
            eventStream.open();

            // replace the header with a customized class
            this.headerView = new MyHeaderView({parentView: this});

            // render the main page
            this.render();

            // start up the router with the `pushState` option enabled
            Backbone.history.start({pushState: true});
        });
    }
});

// initialize the application without starting it
var app = new MyApp({start: false});

// start your application after the page loads
$(function () {
    app.start();
});

Other methods that one may need to override include the following:

bindGirderEvents

Bind handlers to the global events object.

render

Render (or re-render) the entire page.

Note

router.enabled(false) must be set to false to disable URL routing behavior specific to the full Girder web application.

Using Girder Register and Login UI

To use Girder UI components, you will need the following CSS file in your page:

<link rel="stylesheet" href="/girder/static/built/girder_lib.min.css">

To make login and logout controls, provide a dialog container and login/logout/register links, and a container where the dialogs will be rendered:

<button class="btn btn-link" id="login" href="#">Login</button>
<button class="btn btn-link" id="register" href="#">Register</button>
<label class="hidden" id="name" href="#"></label>
<button class="btn btn-link hidden" id="logout" href="#">Logout</button>
<div class="modal fade" id="dialog-container"></div>

In your JavaScript, perform callbacks such as the following:

import { getCurrentUser, setCurrentUser } from '@girder/core/auth';
import events from '@girder/core/events';
import UserModel from '@girder/core/models/UserModel';
import { restRequest } from '@girder/core/rest';
import LoginView from '@girder/core/views/layout/LoginView';
import RegisterView from '@girder/core/views/layout/RegisterView';

$('#login').on('click', function () {
    var loginView = new LoginView({
        el: $('#dialog-container')
    });
    loginView.render();
});

$('#register').on('click', function () {
    var registerView = new RegisterView({
        el: $('#dialog-container')
    });
    registerView.render();
});

$('#logout').on('click', function () {
    restRequest({
        url: 'user/authentication',
        type: 'DELETE'
    }).done(function () {
        setCurrentUser(null);
        events.trigger('g:login');
    });
});

events.on('g:login', function () {
    console.log('g:login');
    var currentUser = getCurrentUser();
    if (currentUser) {
        $('#login').addClass('hidden');
        $('#register').addClass('hidden');
        $('#name').removeClass('hidden');
        $('#logout').removeClass('hidden');
        $('#name').text(currentUser.get('firstName') + ' ' + currentUser.get('lastName'));

        // Do anything else you'd like to do on login.
    } else {
        $('#login').removeClass('hidden');
        $('#register').removeClass('hidden');
        $('#name').addClass('hidden');
        $('#logout').addClass('hidden');

        // Do anything else you'd like to do on logout.
    }
});

// Check for who is logged in initially
restRequest({
    url: 'user/authentication',
    error: null
}).done(function (resp) {
    setCurrentUser(UserModel(resp.user));
    events.trigger('g:login');
});