Routing

The Sapphire server does things other than just routing control to your
application. It also serves static files, routes services, and manages cookies
and sessions.

Application Routing

Applications can have sub-applications, for example, the application games could
have two sub-applications, mahjongg and solitaire, accessed through the urls
"/games/mahjongg" and "games/solitaire". All applications live under the apps
directory in the Sapphire root directory. "apps/games/mahjongg/mahjongg.js"
would be the entry point for the "games/mahjongg"application. All application
files export a single function called getApplication which takes two
parameters, the request and the response. This function should return a promise
that will be resolved with an Application object.

Before the getApplication function is called, a session object and a cookies
object are added both the the request and response parametera. Any changes to
the session object must be explicitly saved. Cookie changes will be updated when
the application is output to the browser. Although cookies can be added to the
cookies object under the request parameter, they should be added to the cookies
object in response.

Static File Routing

There are four types of static files:

Global static files. These are the files available to all applications.
They are in the /public/assets directory off the sapphire root.

Local static files. These are files specific to an application or feature.
They are located under the assets folder for the feature or application.

Page files. These are the page template files; they will be served from
pages directory under the application or feature directory.

Dialog files. These are the dialog template files; they will be served
from the dialogs directory under the application or feature directory.

Service Routing

Service URLs take the following form:

<app>/services/<service>/[...objects]/<method>

Parts

app

The name of the application that implemented the service

service

The name of the service being called

objects

A nested list of objects, for example, building/resources

method

The specific service method being called

Example: /games/services/user/login

To find the service function, the service router looks for a directory named services in the application directory, and within that directory tries to load <service>.js. Each service must export a function or object that corresponds to the first part of the service path. The router will then attempt to drill down into this service object to find the objects specified. For instance, if your service was named account, and you had an object named settings and a method named set, it would look for the presence of settings within the service object. The last part of the route is assumed to be the method name. The router will verify that this is a function, and then call it, passing the request, the response and the post data.

Application Class

Use the Application class to describe your application. Sapphire will use this description to construct the necessary HTML to send to the browser. The overall structure of the HTML document is defined in a file named master.html. This file is a simple outline of the document with placeholders for where various parts of the application will be located. This is the entire default master html file, but for your application can specify a different one.

There are a number of keywords inside curly braces in this file, and these are
used to mark where specific application pieces will be located. This pieces will
be explained below.

Keywords

favicon

The metadata tag to specify the favicon goes here

title

The title tag goes here

metadata

All the specified metadata tags go here

masterCSS

The list of added CSS files go here

headerJS

Once in a while it is necessary to specify a JavaScript file in the html header. These files will go here.

states

States are CSS classes that define the initial state of the application

body

The body is the HTML that specifies the overall chrome for the application. This is stuff outside of the pages. It goes here.

masterJS

All the specified JavaScript files go here

javaScript

The generated JavaScript goes here

initialize

This is the constructor for the application object. It is automatically called
when you create it.

initialize : function(ns, req)

Parameters

ns

Namespace for the application variables

req

the request object from the http server

addState

Call this method to add a state class to the body tag of the HTML file. States
are used to setup initial presentation states for the application. For example,
a login state could configure the application header to display the login
information, rather than a login button.

addState : function(state)

Parameters

state

Name of the state

addVariable

Call this function to add a variable to the application. Variables will be
added to the name space specified when the Application was constructed.

addVariable : function(name, value)

Parameters

name

Name of the variable

value

Value of the variable this should be the native type, not a JSON string

addConfig

Call this function to add a variable to the application that should be assigned
before the JavaScript files are specified. Sometimes JavaScript files will need
information such as the baseUrl for the application to properly initialize.

addConfig : function(name, value)

Parameters

name

Name of the variable

value

Value of the variable, this should be of the native type, not a JSON string

addLink

Call this function to add a link meta tag to the application.

addLink : function(rel, href, type)

Parameters

rel

href

The link.

type

The mime type of the content of the link.

addURL

Call this method to add a URL to the list of managed URLs. URLs will be
available in <namespace>.urls.<name> This can be used to setup the urls for
service calls.

addUrl : function(name, value)

Parameters

name

Name of the url

value

Actual URL itself

setBody

Call this method to set the body file for the application. The body defines the
overall chrome of the application. It should contain an element with the id
pages which specifies where the in the document pages are placed. It should
also contain an element with the id dialogs for the dialogs. If using the
dialogs feature, then an element with the id dialog-overlay should appear
before the dialogs element.

setBody : function(file)

Parameters

file

Path to the file relative to the root of your sapphire directory, for example apps/games/templates/body/html

setMaster

Call this method to set the master file for the application. The master file was
described above. If this function is not called, then a default master file will
be used.

setMaster : function(file)

Parameters

file

Path to the file relative to the root of your sapphire directory, for example apps/games/templates/body/html

addTemplates

Call this method to add templates to the HTML file. The HTML file specified will
be added to the output immediately after the body. Templates will be described
later in this document.

addTemplates : function(file)

Parameters

file

Path to the file – relative to the root of your sapphire directory.

addFileReplacement

Call this method to add a file replacement. In addition to the curly braced
keywords in the master.html file, user defined replacements can exist in
either this file or in the body file. This function will replace the replacement
with the passed name, with the contents of the file specified. This is a bit
like an include file

addFileReplacement : function(name, file)

Parameters

name

Name of the replacement

file

Path to the file – relative to the root of your sapphire directory.

addStringReplacement

Call this method to add a string replacement. In addition to the curly braced
keywords in the master.html file, user defined replacements can exist in
either this file or in the body file. This function will replace the
replacement with the passed name, with the passed string which should contain
valid HTML.

addStringReplacement : function(name, value)

Parameters

name

Name of the replacement

value

Replacement string

addJS

Call this method to add JavaScript files to the application.

addJS : function(files, raw)

Parameters

files

Array of JavaScript files these should be relative to either the apps root, or /public for global files.

raw

Set this value to true if the link should remain unmodified, otherwise it will be cache busted. This would be the case if the linked file existed on a different domain.

addAsyncJS

Call this method to add JavaScript files to the application that will loaded
asynchronously.

addAsyncJS : function(files)

Parameters

files

Array of JavaScript files. These should be relative to either the apps root, or /public for global files.

addCSS

Call this method to add CSS files to the application.

addCSS : function(files)

Parameters

files

The array of CSS files. These should be relative to either the apps root, or /public for global files.

addAsyncCSS

Call this method to add CSS files to the application that will be loaded
asynchronously.

addAsyncCSS : function(files)

Parameters

files

The array of CSS files. These should be relative to either the apps root, or /public for global files.

addPage

Call this method to add a page to the application. Pages will be loaded on demand.

addPage : function(spec)

Parameters

spec

Specification for the page

The spec is an object with a number of fields specifying the details for this page.

Fields

name

Name of the page as it will be referenced in the client

url

Path to the page template file, an HTML file

javascript

Array of JavaScript files that will be loaded the first time a page is shown

css

Array of css files that will be loaded the first time a page is shown

dontPrune

Set this to true if the page should not be pruned. When a page is not pruned it will remain in the DOM even when it is not shown

clone

Set this to true if a new instance of a page should be created every time it is shown

addDialog

Call this method to add a dialog to the application. Dialogs are conceptually
very similar to pages, but function differently. A dialog will be presented in a
modal state and must be dismised before continuing. Dialogs will be loaded on
demand.

addDialog : function(spec)

Parameters

spec

Specification for the page

The spec is an object with a number of fields specifying the details for this dialog.

Fields

name

Name of the dialog as it will be referenced in the client

url

Path to the dialog template file, an HTML file

javascript

Array of JavaScript files that will be loaded the first time a dialog is shown

css

Array of css files that will be loaded the first time a dialog is shown

clone

Set this to true if a new instance of a dialog should be created every time it is shown

addPanel

Call this method to add a loadable panel to the application. Panels are
sub-parts of an application that are not pages or dialogs, but managed
separately. For instance, a page may need many sub-parts, each one standing
alone. Panels are specified using a data structure with the following members

addPanel : function(setName, spec)

Parameters

setName

Name of a panel set where this panel will be used, must be a valid JavaScript identifier

spec

Specification for the page

The spec is an object with a number of fields specifying the details for this panel.

Fields

name

Name of the panel as it will be referenced in the client

url

Path to the panel template file, an HTML file

javascript

Array of JavaScript files that will be loaded the first time a panel is shown

css

Array of css files that will be loaded the first time a panel is shown

setTitle

Call this method to set the title for the HTML document.

setTitle : function(title)

Parameters

title

Title for the given page

addMetadata

Call this method to add metadata tags to the output HTML.

addMetadata : function(name, content)

Parameters

name

name of the metadata

content

content of the metadata

setFavicon

Call this method to set a favicon metadata tag to the HTML.

setFavicon : function(url)

Parameters

url

url of the favicon

Example

Here is example code for an application called sparcade. This application uses
two built in features animated and dialogs. It also includes a dialog named
mj.

Feature Class

A feature is a description part of an application. Features can be reused across
multiple applications. All the instructions to build this part of the
application use paths relative to the path of the feature's javascript file.
Use the Feature class to create a feature.

The methods of the Feature class mirror methods in the Application class, but
any relative paths specified in any of these methods will be modified to point
to the feature directory.

The Feature class is implemented as a convenience, so that paths do not need to
be duplicated multiple places, and so that the feature can be more easily
relocated.

Notice that all the files local to the feature are specified with relative paths,
while those that are outside of the feature, such as shared JavaScript and CSS
files are specified with an absolute path.

This example is implemented using promises, which allows the main application to
include this feature as part of a promise chain.

Services

Service functions must return a Q promise that will be fulfilled when the
service function is complete. This makes it easier for the service router to
capture errors and return a properly formatted response. Server responses are
assumed to be in JSON.

Sapphire has a Service class that can be used to protect against cross site
request forgery. This service class restricts service functions to be one
level deep, but is typically good enough.

Here is an example services using the Services class, this would be called by posting to the url: /sample/services/user/login

Standard Responses

Sapphire applications are written with a standard response format in mind.
Responses are in JSON, with the top level items being:

Repsonse

success

Will be true or false if the function succeeded. Results that return an empty set should be considered successful. Only problems with the request like missing data, or database errors, should be considered failures

result

This is the result of the service call. It can be any data type

In addition to these two standard members, others can be added to the top level of the response. These can be intercepted in the client to look for global level changes, like the user identity changing.

Directory Organization

The directory structure for sapphire is organized like this:

Each application also has a directory structure:

assets/ static assets for your application:

js

css

images

**/ sub application directories

features/ features go here

pages/ page features go here

dialogs/ dialog features go here

services/ services go here

node_modules/ needed packages go here

templates/ html template files

The directory structure for features and dialogs are similar to applications: