Introduction to the Javascript API

Contents

  1. Overview
  2. App Setup
  3. Organization
  4. Authentication
  5. Important Features
  6. Versioning

Overview

The purpose of the v3 Javascript API is to provide powerful functionality for interacting with your Jive instance from within a Jive App. The v3 API provides far more features than the previous v2 API. Almost any action that can be performed through the user interface can be done programmatically using the v3 API. The API also exposes some functionality of the Admin Console. Extensive metadata about the available Classes and Static Methods can be obtained with the metadata  static class.

All requests and responses use JSON data with attached javascript methods. The JSON format for different Jive objects is given in the Classes section (see sidebar). Fields marked as required must be specified when creating and updating objects. Optional fields can be specified on create and update, but the request will succeed whether or not they are provided. Fields marked as read-only are returned as data in responses. Read-only fields will be ignored for create requests. When updating an entity, fields marked as required and optional can be modified, but read-only fields should not be modified. As an example, the Document page describes the full JSON format for a document. The documents static method page gives the minimum JSON for creating a new document.

The most important types and methods in the API fall into four categories:

  • Content
  • Places
  • People
  • Activity

Content includes the Classes Document, DiscussionPoll, and Post  (see "Classes" in the sidebar.) Static classes to manipulate content include contents, discussionspolls, etc. These must be prefixed with namespace osapi.jive.corev3. The contents static class is special in that it can perform any static functionality provided by the more specific static classes (e.g. discussions). The type field must be provided when using the contents static class.

Place Classes include Blog, GroupProject, and Space. Static classes for manipulating places include blogs, places, groups, and projects. The places static class can perform any functionality provided by the other static place classes.

People, or Jive users, are manipulated with the Person Class and the people Static Class. The Member Class and members  Static Class are used for adding users to groups.

Classes related to Activity include Action, ActivityInboxEntry, and StreamEntry. Similar to Content, Places, and People, there are corresponding static classes.

App Setup

The only requirement is to add the following line to your app.xml file inside ModulePrefs.
<ModulePrefs>
...
    <Require feature="jive-core-v3" />
...
</ModulePrefs>

Organization

The v3 Javascript API is organized into three main sections:

  • Static Classes
  • Classes
  • Extendable

Static Classes

The artifacts that are listed under "Static Classes" are collections of static functions that are used as entry points into the API. These methods are generally used to obtain instances of the non-static classes; however, there are some operations that can be done directly with the static functions.

For example, to get a person, the following code can be used:

// get the request that will fetch a person by username
var request = osapi.jive.corev3.people.get({username: 'admin'});
// execute the request
request.execute(function(response) {
  if (response.error) {
    var code = response.error.code;
    var message = response.error.message;
    // present the user with an appropriate error message
  } else {
        var person = response;
        // use the person object as appropriate
  }
});

Classes

The artifacts that are listed under "Classes" provide an object oriented view of the Jive system. Instances of these classes are never constructed directly. They are obtained through calls to one of the static class methods. Once an instance is obtained, the properties and methods of that class can be accessed in the standard Javascript fashion.

For example, if a person is obtained as described above, that person's blog can be obtained directly from the person object:

// ensure that blog is accessible
if (person.getBlog)
  // get the request that will fetch the user's blog
  var request = person.getBlog();
  // execute the request
  request.execute(function(response) {
    if(response.error) {
      var code = response.error.code
      var message = response.error.message
      // present the user with an appropriate error message
    } else {
      var blog = response;
      // use the blog object as appropriate
    }
  });
}

Extendable

The artifacts that are listed under "extendable" are not first class elements in the Core API. That is, they can not be instantiated or manipulated directly. Instead they are used to add compound fields to the non-static classes. For example, the ContentBody item is used to encapsulate the content body of a Jive content object, which in turn has type and text fields.

Authentication

In order to use the Core API, the user running the app needs to be authenticated with the Jive container. The way that this happens is outside of the scope of this API. It is generally done by logging into Jive via the web UI. Once this is done, the app and all of its Core API calls run with the permissions of that logged in user.

If the current user does not have permission to perform an action, then the corresponding method will be undefined. For example, if the current user does not have permission to delete a person, then the destroy function will be undefined on that person entity.

Important Features

Jive Request Objects

How they work

Throughout the Javascript API, it is implied that any function (static or non-static) returns a Jive request object. Making requests with Jive request objects is similar to using jQuery.ajax() or XMLHttpRequest objects. However, the process is simplified somewhat and there are important differences. The requests are always asynchronous, and a callback function taking a single argument must be specified. Since the request is performed inside an app container, the returned objects have functions specific to Jive rather than being purely data objects. There are no separate success and error callbacks---the user must check if an error occurred. If an error occurred, the error field will exist. Otherwise, a Jive entity is returned, typically the object created, updated, or fetched. The only exception is that requests to destroy an object return a simple JSON with a  status  field that should have the value ‘204’ (no content) if the request succeeded. Following is an example response if an invalid date is given with a create request (see  date format):
{
   "error":{
      "code":400,
      "message":"Invalid date format 2012-07-05"
   },
   "status":400
}
The typical workflow:

  1. Setup the JSON required to perform the request, e.g. see announcement creation  for the minimal JSON required to create an announcement. See documentation on individual entities for fields that can be used on create and update.
    • In the case of updating an entity, use the existing entity. Modify the fields to be updated before obtaining the request object with var request = someEntity.update().
  2. Obtain a request object
  3. Call execute() on the request object, passing in the required callback
See examples throuhgout this document for how to perform requests.

Batch requests

To improve performance when performing multiple requests, batch requests are possible. This is done by obtaining a new batch object, and then adding key-value pairs where the values are Jive request objects. For example, the following code would create 3 announcements:
function createAnnouncements() {
    var announcement1 = {
        subject : "A test announcement 1",
        content : {text:"<p>Test Announcement 1</p>"}
    };
    var announcement2 = {
        subject : "A test announcement 2",
        content : {text:"<p>Test Announcement 2</p>"}
    };
    var announcement3 = {
        subject : "A test announcement 3",
        content : {text:"<p>Test Announcement 3</p>"}
    };

    var batch = osapi.newBatch();
    batch.add("announcement1", osapi.jive.corev3.announcements.create(announcement1));
    batch.add("announcement2", osapi.jive.corev3.announcements.create(announcement2));
    batch.add("announcement3", osapi.jive.corev3.announcements.create(announcement3));

    batch.execute(function(data) {
        if (data.error) {
            //handle error
        }
        console.log("First announcement's subject: " + data["announcement1"].subject);
        console.log("Second announcement's subject: " + data["announcement2"].subject);
        console.log("Third announcement's subject: " + data["announcement3"].subject);
    });
}

Paginated Lists

Throughout the API, methods that return arrays of objects return special Jive Paginated Lists. These objects always contain the following fields:

PropertiesTypeDescription
listJSON ArrayArray containing the retrieved Jive objects
startIndexintegerThe current page's offset into the list of all results
itemsPerPageintegerThe max number of items returned per page. Usually set with the count   query parameter.
linksJSON ObjectObject containing URLs for getting the next or previous page of results. Has fields next  and prev (when available).
These objects contain a paginated list of Jive objects including metadata such as the items per page and the current starting index into the search results. For example, the static method osapi.jive.corev3.people.get returns a list object represented by the type Person[], not to be confused with a Javascript array type. List objects have a getNextPage function that returns a request to get the next page of objects. Note that this function is undefined when there are no more results to retrieve, so you must check if it exists when retrieving multiple pages. For example, to get a list of places with 1 item per page, one could execute the following code:

// get the request to retrieve a list of places, 1 per page
var request = osapi.jive.corev3.places.get({count: 1});
// execute the request
request.execute(function(response) {
  if (response.error) {
    var code = response.error.code;
    var message = response.error.message;
    // present the user with an appropriate error message
  } else {
      var place1 = response.list[0];
    // process the first place returned
  }
});

Example JSON of a returned list object containing a single blog (resources omitted for brevity):

  {   
   "startIndex":0,
   "links":{
      "next":"places?sort=titleAsc&fields=%40all&count=1&startIndex=1"
   },
   "itemsPerPage":1,
   "list":[
      {
         "type":"blog",
         "status":"Active",
         "parent":"/people/2355",
         "contentTypes":[
            "post"
         ],
         "id":"1195",
         "visibleToExternalContributors":false,
         "updated":"2012-08-10T15:52:59.707+0000",
         "description":"Description of some blog created on  Fri Aug 10 2012 08:52:59 GMT-0700 (PDT)",
         "name":"Blog created at Fri Aug 10 2012 08:52:59 GMT-0700 (PDT)678245",
         "displayName":"Some_blog_872404",
         "published":"2012-08-10T15:52:59.707+0000",
         "followerCount":1,
         "viewCount":0
      }
   ]
}

As an advanced example, here is sample code to recursively process elements of a list by page:

//Argument: a request object that returns a Jive list
function processListByPage(request) {
    //Execute the request to get a list
    request.execute(function(response) {
        if (response.error) {
            var code = response.error.code;
            var message = response.error.message;
            // present the user with an appropriate error message
        } else if (!response.list) {
            alert("Error: response is not a list!");
        } else {
            for (var i = 0; i < response.list.length; i++) {
                //Process each element in this page
            }
            if (response.getNextPage) {
                var requestNextPage = response.getNextPage();
                processListByPage(requestNextPage);
            }
        }
    });
}

Date Format

The Date format used is based on the ISO 8601 standard, but has additional restrictions. The time field and the timezone must be included. For example, September 1st 2012, 11 AM in GMT would be written as 2012-09-01T11:00:00.000+0000. Note that the UTC offset is required, because Jive uses UTC time to avoid ambiguity. In this case the offset is +0000 for GMT. The milliseconds are also required. Since Jive 6.0.3 and above, Jive provides static methods for parsing and formatting dates. The methods are  osapi.jive.corev3.parseDate(dateString) and osapi.jive.corev3.formatDate(aDate).

osapi.jive.corev3.parseDate   is specifically for parsing dates returned from Jive in JSON objects, but it will fall back to using the standard Javascript date parsing, so you can use it throughout your code. It returns null on failure. For versions prior to Jive 6.0.3, most browsers can parse ISO 8601 dates, so using the Date class's constructor should work on the dates returned from Jive inside JSON objects. If this fails, you can use sample code at the bottom of this section. Here is an example of retrieving a document and parsing the publish date.
var request = osapi.jive.corev3.documents.get();
request.execute(function(docs) {
    var firstDoc = docs.list[0];
    var datePublished = osapi.jive.corev3.parseDate(firstDoc.published);
    console.log("Parsed a document's publish date from Jive: " + datePublished);
});
osapi.jive.corev3.formatDate is for converting a Javascript Date object into a string suitable for sending to Jive. There are several cases where you can provide a date, such as when choosing the endDate for an announcement. Here is an example of creating an announcement, providing the current date + 10 days as the endDate
var endDate = new Date();
endDate.setUTCDate(endDate.getUTCDate() + 10);
var dateString = osapi.jive.corev3.formatDate(endDate);

var announcement = {
        subject : "A test announcement to expire in 10 days",
        content : {text:"<p>Test Announcement</p>"},
        endDate: dateString
    };
var request = osapi.jive.corev3.announcements.create(announcement);
request.execute(function(created) {
    console.log("Created this announcement", created);
});
To format a Date object when osapi.jive.corev3.formatDate is not available (before Jive 6.0.3), the following function can be used:
 function formatJiveDate(date) {

    if (Date.prototype.toISOString) {
        return date.toISOString().replace(/Z$/, "+0000");
    }

    function pad(number) {
        var r = String(number);
        if ( r.length === 1 ) {
            r = '0' + r;
        }
        return r;
    }

    return date.getUTCFullYear()
        + '-' + pad( date.getUTCMonth() + 1 )
        + '-' + pad( date.getUTCDate() )
        + 'T' + pad( date.getUTCHours() )
        + ':' + pad( date.getUTCMinutes() )
        + ':' + pad( date.getUTCSeconds() )
        + '.' + String( (date.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
        + '+0000';
}
To parse a date string when osapi.jive.corev3.parseDate is not available (before Jive 6.0.3), the following function can be used:
var dateRegex=/(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)\.(\d\d\d)\+0000/;

function parseJiveDate(dateString) {

    //First try to match the strict date format from Jive
    var match = dateRegex.exec(dateString);
    if (!match) {
        //On fail, fall back to default date parsing
        return new Date(dateString);
    }
    var year = parseInt(match[1]);
    var month = parseInt(match[2]) - 1; //javascript expects a month between 0 and 11
    var day = parseInt(match[3]);
    var hour = parseInt(match[4]);
    var min = parseInt(match[5]);
    var s = parseInt(match[6]);
    var ms = parseInt(match[7]);

    var d = new Date();
    d.setUTCFullYear(year, month, day);
    d.setUTCHours(hour, min, s, ms);

    return d;
}
To parse ISO 8601 dates in Java, see the REST API documentation.

Filters and Searching

Throughout the API, requests to get paginated lists of objects provide filters and search functionality for improving the results. For example, the static method contents.get allows for the filters author, count, fields, placesearch, startIndex, tag, and type. The count and startIndex fields are described above for paginated lists. Providing the search field performs a search based on text in the content of objects, typically searching the subject, description, and content or content.text fields (for types containing these fields). The search field supports wild cards. For example, if you want to search for "Bob Smith Jones" but you don't know that his middle name is "Smith", then you can search for "Bob*Jones".

Versioning

Some classes and methods have a Since label that identifies which iteration of the Core API this feature was added in. Items with no Since label have been available in Jive Cloud since the Summer 2012 refresh. Other values have the following meaning:

  • Since: 3.0 - Available in Jive 6.0, and late 2012 in Jive Cloud.