JavaScript Cookbook

Getting Started

To get started with the JavaScript driver, please visit the Cloud CMS JavaScript Driver Page.

Connecting to Cloud CMS

To connect, supply your API Keys as the argument to the connect() method.

Gitana.connect({
    "clientKey": "{clientKey}",
    "clientSecret": "{clientSecret}",
    "username": "{username}",
    "password": "{password}",
    "baseURL": "https://api.cloudcms.com"
}, function(err) {

    var platform = this;

});

If a problem was encountered during the authentication, the err variable will be populated. If not, the this variable will the Platform instance you can use to start doing interesting things!

If you supply an application argument in your API Keys, you'll get back a helper object that you can use to access all of the resources on your application's associated Stack.

Gitana.connect({
    "clientKey": "{clientKey}",
    "clientSecret": "{clientSecret}",
    "username": "{username}",
    "password": "{password}",
    "baseURL": "https://api.cloudcms.com"
}, function(err) {

    var helper = this;

    var repository = helper.datastore("content");    

});

Asynchronous Chaining

The Cloud CMS JavaScript driver is unique and unusual in that it offers a Chaining based solution to making asynchronous series of API calls. It's similar to Promises (but pre-dates them!) and makes it possible to make a series of API calls without having to write as much code.

For example, with the Cloud CMS JavaScript driver, you can write the following:

platform.readRepository("1234567890abcdef1234").readBranch("master").then(function() {
    this.createNode({"title": "Article #1"});
    this.createNode({"title": "Article #2"});
    this.createNode({"title": "Article #3"});
});

This might look similar to Promises but it has a few differences. One important difference is that the then() method modifies the this to be the result. This allows you to chain calls as shown above, or even like this:

platform.readRepository("1234567890abcdef1234").readBranch("master").createNode({"title": "Article #1"});

Which is effectively the same, in concept, as a callback approach where you might do something like:

readRepository(platform, function(err, repository) {

    if (err) {
        return handleError(err);
    }

    readBranch(repository, "master", function(err, branch) {

        if (err) {
            return handleError(err);
        }

        createNode(branch, {"title": "Article #1"}, function(err, node) {

            if (err) {
                return handleError(err);
            }

            // yay I made it!

        });
    })'
});

Not so with our JavaScript driver. You can keep your code lean and clean. You just need to be mindful of the changes in scope (the this variable). Which is unique. But there it is.

Code Samples

Here are some code samples to help you get started.

In these examples, we'll assume that you're connecting to Cloud CMS using API keys that either provide the application value or they do not. The examples below show an essentially skeleton for a JS application that uses the driver for both cases.

In all of the examples that follow, assume that your code gets inserted into the TODO section.

In Cloud CMS, you can have as many repositories as you'd like. And each repository can multiple branches (similar to Git). The first thing you should do is connect and get the branch that you want to work on.

For cases where the repository and branch must be explicitly referenced, we'll assume that the repository ID is 1234567890abcdef1234 and the branch ID is master.

API Keys with application

Gitana.connect({
    "clientKey": "{clientKey}",
    "clientSecret": "{clientSecret}",
    "username": "{username}",
    "password": "{password}",
    "baseURL": "https://api.cloudcms.com",
    "application": "{yourApplicationID}"
}, function(err) {

    if (err) {
        return console.log("Failed to connect", err);
    }

    var helper = this;

    var repository = helper.datastore("content");

    repository.readBranch("master").then(function() {
        var branch = this;

        // TODO: add your custom code here
    });    

});

Standard API Keys (without application)

Use the readRepository method to fetch a specific repository. The user you've logged in as must have READ permissions to the repository. If they do not have read rights, a null response is expected.

Use the readBranch method to fetch a specific branch. The user you've logged in as must have READ permissions to the branch. If they do not have read rights, a null response is expected.

Gitana.connect({
    "clientKey": "{clientKey}",
    "clientSecret": "{clientSecret}",
    "username": "{username}",
    "password": "{password}",
    "baseURL": "https://api.cloudcms.com"
}, function(err) {

    if (err) {
        return console.log("Failed to connect", err);
    }

    var platform = this;

    platform.readRepository("1234567890abcdef1234").then(function() {
        var repository = this;

        this.readBranch("master").then(function() {
            var branch = this;

            // TODO: add your custom code here
        });    
    });

});

Node Creation

Create a Node

Create a basic node of type n:node (the default type).

var branch = this;

branch.createNode({
    "title": "My First Node"
}).then(function() {

    // NOTE: this = node

    // add your custom code here
});            

Create a Node for a Custom Content Type

Suppose we have a custom content type called custom:article that looks like this:

{
    "title": "Custom Article",
    "_qname": "custom:article",
    "type": "object",
    "properties": {
        "title": {
            "type": "string"
        },
        "body": {
            "type": "string"
        },
        "categories": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "rating": {
            "type": "number"
        }
    }
}

Create a content instance of this type like this:

var branch = this;

branch.createNode({
    "_type": "custom:article",
    "title": "Article #1",
    "body": "A still more glorious dawn awaits",
    "categories": ["category1", "category2", "category3"],
    "rating": 5            
}).then(function() {

    // NOTE: this = node

    // add your custom code here
});            

Create a Folder

In Cloud CMS, folders are just nodes with the f:container feature on them.

var branch = this;

branch.createNode({
    "title": "My Folder",
    "_features": {
        "f:container": {}
    }
}).then(function() {

    // NOTE: this = node

    // add your custom code here
});            

If you want your folder to appear in the general folder hierarchy, you must link it to a parent folder that is already a member of the folder hierarchy. The main folder hierarcy descends from the branch root node.

Here is the long way of doing this:

var branch = this;

branch.rootNode().then(function() {

    var rootNode = this;

    Chain(branch).createNode({
       "title": "My Folder",
       "_features": {
           "f:container": {}
       }
    }).then(function() {
        var folder = this;

        Chain(rootNode).associate(folder, {
            "_type": "a:child"
        }).then(function() {
            // done!
        });
    });

});   

An easier way to do this is to use the following special properties when the node is created:

  • _parentFolderPath - the path to the parent folder where the created node should be linked. The folder must exist. If it does not exist, the operation will fail.
  • _fileName - the f:filename to be assigned to the node once it is created.

Alternatively, you can use:

  • _filePath - an absolute path where the file should be created. This allows you to specify the parent folder path and the file name at the same time,.

You can also adjust the association type (between the discovered parent folder and your newly created item).

  • _associationTypeString - the QName for the newly created association. The default is a:child.

Thus, you could do:

var branch = this;

branch.createNode({
   "title": "My Folder",
   "_features": {
       "f:container": {}
   },
   "_parentFolderPath": "/",
   "_fileName": "my_folder"
}).then(function() {
    var folder = this;        
});

Or you could do:

var branch = this;

branch.createNode({
   "title": "My Folder",
   "_features": {
       "f:container": {}
   },
   "_parentFolderPath": "/",
   "_filePath": "/my_folder"
}).then(function() {
    var folder = this;        
});

Read a Node

You can read a previously created node if you have its ID:

var branch = this;

branch.readNode("myNodeId").then(function() {
    var node = this;
});

You can also read a node by its relative path. To do this, you must pass a node ID and a path offset. The node ID can be "root" if you want to start from the top level directory. Assume we have a node with path /myFolder/myNode. To read it:

var branch = this;

branch.readNode("root", "/myFolder/myNode").then(function() {
    var pathNode = this;
});

If you have the ID of a multilingual node, you can read localizations of the node by passing a "locale parameter". For example, to read a node's Spanish translation, you could do something like this:

var branch = this;

branch.readNode("myNodeId", null, { locale: "es_ES" }).then(function() {
    var spanishNode = this;
});

Query for Nodes

Let's now look at querying for content. This makes use of MongoDB's query language to express some pretty powerful queries. We recommend further reading on Query within Cloud CMS.

Let's assume that we have the following:

  • Article #1
{
    "_type": "custom:article",
    "title": "Article #1",
    "body": "a mote of dust suspended in a sunbeam",
    "categories": ["category1", "category2"],
    "rating": 1
}
  • Article #2
{
    "_type": "custom:article",
    "title": "Article #2",
    "body": "harvesting star light",
    "categories": ["category2", "category3"],
    "rating": 2
}
  • Article 3
{
    "_type": "custom:article",
    "title": "Article #3",
    "body": "we are star stuff",
    "categories": ["category3", "category1"],
    "rating": 3
}

Basic Querying

Find all of the articles that have a category with the value category1.

var branch = this;

branch.queryNodes({
    "_type": "custom:article",
    "category": "category1"
}).count(function(c) {
    console.log("The size was: " + c);
}).each(function() {
    console.log("Found a result, title: " + this.title + ", rating: " + this.rating);
}).then(function() {
    // done!
});

Pagination

If you have a lot of potential query hits, you'll want to paginate. Here is an example where we return results starting at index 2 and hand back at most 5 results.

var branch = this;

branch.queryNodes({
    "_type": "custom:article",
    "category": "category1"
}, {
    "skip": 2,
    "limit": 5    
}).each(function() {
    console.log("Found a result, title: " + this.title + ", rating: " + this.rating);
}).then(function() {
    console.log("The size was: " + this.size()); // 1
    console.log("The offset was: " + this.offset()); // 2
    console.log("The totalRows was: " + this.totalRows()); // 3
});

Sorting

Use the pagination option to sort the results as you see fit. Here we sort descending on rating.

var branch = this;

branch.queryNodes({
    "_type": "custom:article",
    "category": "category1"
}, {
    "sort": {
        "rating": -1
    }   
}).each(function() {
    console.log("Found a result, title: " + this.title + ", rating: " + this.rating);
});

The results will look like:

Found a result, title: Article #3, rating: 3
Found a result, title: Article #2, rating: 2
Found a result, title: Article #1, rating: 1

Query for values in a range

Find all of the articles where the rating is greater than or equal to 2.
This demonstrates the power of MongoDB's query language.

var branch = this;

branch.queryNodes({
    "_type": "custom:article",
    "rating": {
        "$gte": 2
    }
}).each(function() {
    console.log("Found a result, title: " + this.title + ", rating: " + this.rating);
});

Search for Nodes

Let's now look at searching for content. This makes use of Elastic Search's DSL to express some very powerful full text and structured searches. We recommend further reading on Search within Cloud CMS.

We also suggest reading up on Query Strings to understand how you can write searches textually (in addition to structuring them as JSON objets):

Let's assume that we have the following:

  • Article #1
{
    "_type": "custom:article",
    "title": "Article #1",
    "body": "a mote of dust suspended in a sunbeam",
    "categories": ["category1", "category2"],
    "rating": 1
}
  • Article #2
{
    "_type": "custom:article",
    "title": "Article #2",
    "body": "harvesting star light",
    "categories": ["category2", "category3"],
    "rating": 2
}
  • Article 3
{
    "_type": "custom:article",
    "title": "Article #3",
    "body": "we are star stuff",
    "categories": ["category3", "category1"],
    "rating": 3
}

Find all of the nodes with the word star. Simple enough!

var branch = this;

branch.searchNodes("star").each(function() {    
    console.log("Found a result, title: " + this.title + ", rating: " + this.rating);
});

The results will be:

Found a result, title: Article #2, body: harvesting star light
Found a result, title: Article #3, body: we are star stuff