Skip navigation

Developer

1 Post authored by: craig.mcclanahan Employee

Let's face it: The V3 API is AWESOME!!! When we set out to create V3, we had one ambitious goal: Anything the Jive UI could do, you could do with V3. On top of that, we wanted to make sure we incorporated all of the "lessons learned" and put forth an incredible, new API, not just some incremental improvements. The result is an API that opens up the entire Jive platform and allows developers amazing new power and flexibility. While we are not at 100% of our goal yet, we are pretty darn close. Over the next few releases you'll see continued improvement and new capabilities added to the API. This is the first post in a series, so if you've got a topic on REST you'd like covered, feel free to post a comment. So now we'll start by sharing a few of the cool and fun things you can do with the API.

 

A bit of background...

Before we get started, cover a bit of background about the REST APIs. As we built the APIs, we wanted to conform with the best practices and principles as REST as we possibly could. For example, one thing you'll notice is that wherever possible, you'll get a link to other objects in Jive, typically, this will be in the "resources" information that is returned from one of the calls.

From: Jive REST API v3.3

All REST endpoints use JSON in the request and response bodies. The JSON format for different Jive objects is provided in the Types section. Fields marked as requiredmust 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 and will be ignored if included in a POST or PUT request. As an example, the Announcement page describes the JSON format for an announcement. It also gives the minimum JSON for creating a new announcement with a POST.

jive_devslanding_transparent.png

Let's get started...

 

Based on questions and comments in the developer community, feedback from our Professional Services team, and by throwing darts at a dartboard, here are some of the more interesting things you can do with the REST API. All of these examples use CURL. You can simply substitute in your own user id and password and have fun.

Note: These commands WILL WORK, so make sure you don't issue them against your production version of Jive until you are sure that's what you want to do. You may want to try sandbox.jiveon.com first, just to be sure!

 

In the examples below, note the following common conventions:

  • Replace {credentials} with either {username}:{password} or, if you don't want to show your password in clear text, just enter {username}.  Curl will then prompt you for the password, without echoing it.
  • I like to use the --include option so that the response includes the HTTP status, and any included headers, as well as the response body.  This is useful in debugging why you got a particular response.
  • All responses that return a response body add the line throw 'allowIllegalResourceCall is false.'; at the beginning.  This is to avoid cross site scripting attacks, and will need to be stripped off before you parse the JSON.
  • A good habit is to always enclose the URL in single quotes.  This avoids problems with the shell interpreting "&" between query parameters as it normally would.
  • For readability, we can leverage the shell's backslash ("\") character to continue the command on the next line.  Be sure you do not insert spaces where they are not intended when doing this.

 

Optimize search using parameters

 

One of the most powerful APIs is the search service, which allows you to search for people, places, or contents using a variety of filter criteria.  The most basic way to perform this search is something like this:

curl --include --user {credentials} 'https://sandbox.jiveon.com/api/core/v3/search/contents?filter=search(test)'

 

What you will get back is a list of matching content (in this case) items, including the complete text body of each item.  In addition, there are some fields specific to search results that are oriented towards enabling the creation of a client UI without having to go back and get more information for each match:

  • highlightBody -- a snippet of the body content, with matching keywords highlighted (only present if there were keyword matches in the body content).
  • highlightSubject -- a snippet of the subject, with matching keywords highlighted (only present if there were keyword matches in the subject).
  • highlightTags -- a snippet of the tags for this content object, with matching keywords highlighted (only present if there were keyword matches in the tags).
  • parentContent -- if the match occurred in a message (reply to a discussion) or comment (reply to a document or blog post), a summarized version of the original discussion, document, or blog.
  • parentPlace -- if the matching content object resides in a particular Jive place, a summarized version of that place.  If the content object is personal content for a user, this will be a summarized version of the owning user.

 

Armed with this information, it turns out you can create a compelling user interface for searching, without even needing the actual content body.  Can we improve performance by telling Jive not to return the body, since we don't need it?  It turns out that the Jive UI does exactly this -- it uses the fields query parameter (available on nearly every Core API V3 endpoint) to specify exactly the fields to be returned.  You can see this in action by turning on the developer console in your browser, selecting the network view, and navigating to the search page (https://sandbox.jiveon.com/search.jspa).  Now, type "test" into the search box, and click the Search button.  In the console, you can see that the UI did a Core API V3 search request equivalent to the following curl command:

curl --include --user {credentials} \

'https://sandbox.jiveon.com/api/core/v3/search/contents?collapse=true&\

fields=rootType,type,subject,author,question,answer,parentPlace,parentContent,highlightSubject\

highlightBody,highlightTags,published,updated,replyCount,likeCount,viewCount,\

visibleToExternalContributors,binaryURL&filter=search(test)'

 

Besides your client not having to deal with a bunch of information that it is not interested in, doing this will also improve performance on the Jive server, because it avoids the need to render the body content to HTML.

 

The same principle applies to virtually every request -- you can list the individual fields you are interested in.  There are also some common shorthands for field lists that are defined by the server:

  • @all -- Return all fields (this is the default on requests for an individual object)
  • @summary -- Return a summary set of fields for each object (this is usually the default on requests that return multiple objects.

Note that the type and resources fields are always returned, because it is always important to know what type of object you are processing, as well as discover related resource URIs.

 

Pagination


As we examine the results from our search request above, we see that it follows this general format:


{

   "list" : [

       { ... object ... },

       { ... object ... },

       ...

   ],

   "startIndex" : 0,

   "itemsPerPage" : 25,

   "links" : [

       "next" : "https://sandbox.jiveon.com/...&count=25&startIndex=25"

   ]

}

 


The main fields of interest are:

  • list -- an array containing one entry for each returned object (use the type field inside that object to understand what kind of object it is)
  • startIndex -- the starting index that you specified to get paginated results starting from that (zero relative) index.  If you did not specify this query parameter, it defaults to zero.
  • itemsPerPage -- the maximum number of objects to be returned (specified by the count query parameter, and generally defaulting to 25 if not specified.
  • links -- an array of useful URIs you can use to navigate to the next or previous (if any) page in the list:
    • next -- a URI for the next page (note that the startIndex value has been updated for you)
    • previous -- if you are not on the first page, a URI for the previous page.

 

This style is used for endpoints that return results where it makes sense to use indexing to perform pagination.  A different style is used for results like activity stream entries, where you are might be more interested in polling for activities that have occurred since the last time that you asked, or within a particular time frame.  This is accomplished by using the after or before query parameters to specify the relevant limits.

 

If we perform a request for the most recent activities:

curl --include --user {credentials} 'https://sandbox.jiveon.com/api/core/v3/activities'

we will receive results that include modified versions of the links:

 

{

   "list" : [ ... ],

   "itemsPerPage" : 25,

   "links" : [

      "next" : "https://sandbox.jiveon.com/api/core/v3/activities?fields=%40all&count=25&before=2013-04-16T04%3A23%3A14.374%2B0000",

      "previous" : "https://sandbox.jiveon.com/api/core/v3/activities?fields=%40all&count=25&after=2013-04-16T17%3A56%3A08.692%2B0000"

   ]

}

 

The URIs that are returned contain the ISO 8601 formatted timestamp for polling backwards in time ("next") or forwards in time ("previous").  As an additional note, you'll see that the parameter values have been URL encoded.  Curl is nice enough to do this for you, but you'll need to take care to URL encode each query parameter value yourself.


Creating a group

 

So far, we have used curl and the Core API V3 to retrieve information.  Now let's go create something -- in particular, let's create a social group.  A few notes will help us understand how creating things work:

  • The input request body is generally a JSON data structure, exactly what you get back after you create the object.  (The exception to this is when you use a multipart request to create a content object and associated attachments, which will be discussed later).
  • We must explicitly tell curl to use a content type of application/json for the request body.  This will also be true using whatever client technology your application uses, because Jive matches your request to the correct processing logic based on a combination of:
    • HTTP verb
    • Request URI
    • Request content type
  • The Core API follows the usual REST convention of using the POST verb to create things, posting to a URI that represents a collection of those objects.
  • Successful creation of an object will return an HTTP 201 ("Created") status, with a Location header that contains the URI (from the Core API perspective) of the new object.
  • In addition, as a convention, Core API returns the JSON representation of the newly created object in the response body, with any default values filled in, plus resource URIs for related resources.
  • When you create a content object or a place, you are using a common URI for each (/api/core/v3/contents or /api/core/v3/places).  Therefore, you must include a type field to define what type of object you are creating.

 

OK, we want to create a social group.  The first thing to do is consult the documentation on the group entity to see which fields are required and which ones are optional.  (Attempts to set a value for a field labelled read only in the documentation will be silently ignored.).  For a group, we must provide values for the displayName, groupType, name, and type fields.  Let's use a curl command like this:

 

curl --include {credientials} --header 'Content-Type: application/json' -X POST \

--data '{ "displayName" : "craig-open-group", "groupType" : "OPEN", "name" : "Craig Open Group", "type" : "group" }' \

'https://sandbox.jiveon.com/api/core/v3/places'

 

If you try this command without modifying anything, you will get a 409 ("Conflict") error, because a group with the same name already exists (I beat you to it ), so be sure to change the display name and name fields to some unique values.  If, on the other hand, you have changed the displayName and name fields to something both unique and acceptable, you'll get a 201 ("Created") response back, along with the complete representation of the newly created group.

 

{

  "type" : "group",

  "memberCount" : 1,

  "creator" : {

    "name" : {

      "givenName" : "Craig",

      "familyName" : "McClanahan",

      "formatted" : "Craig McClanahan"

    },

    "type" : "person",

    "displayName" : "Craig McClanahan",

    "jive" : {

      "level" : {

        "name" : "Newbie",

        "points" : 15

      },

      "username" : "craigmcc"

    },

    "resources" : {

      "reports" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/@reports",

        "allowed" : [ "GET" ]

      },

      "manager" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/@manager",

        "allowed" : [ "GET" ]

      },

      "self" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053",

        "allowed" : [ "PUT", "GET" ]

      },

      "tasks" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/tasks",

        "allowed" : [ "GET", "POST" ]

      },

      "avatar" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/avatar",

        "allowed" : [ "GET" ]

      },

      "colleagues" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/@colleagues",

        "allowed" : [ "GET" ]

      },

      "followers" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/@followers",

        "allowed" : [ "GET" ]

      },

      "following" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/@following",

        "allowed" : [ "GET" ]

      },

      "images" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/images",

        "allowed" : [ "GET", "POST" ]

      },

      "html" : {

        "ref" : "https://sandbox.jiveon.com/people/craigmcc",

        "allowed" : [ "GET" ]

      },

      "streams" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/streams",

        "allowed" : [ "GET", "POST" ]

      },

      "followingIn" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/followingIn",

        "allowed" : [ "GET" ]

      },

      "activity" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/people/2053/activities",

        "allowed" : [ "GET" ]

      },

      "members" : {

        "ref" : "https://sandbox.jiveon.com/api/core/v3/members/people/2053",

        "allowed" : [ "GET" ]

      }

    },

    "id" : "2053"

  },

  "groupType" : "OPEN",

  "name" : "Craig Example Group",

  "displayName" : "craig-example-group",

  "description" : "",

  "status" : "Active",

  "contentTypes" : [ "blog", "documents", "files", "discussions", "polls", "projects", "updates", "ideas", "videos" ],

  "viewCount" : 1,

  "published" : "2013-04-17T00:42:24.192+0000",

  "updated" : "2013-04-17T00:42:24.305+0000",

  "visibleToExternalContributors" : false,

  "tags" : [ ],

  "followerCount" : 1,

  "resources" : {

    "invites" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/invites/places/3208",

      "allowed" : [ "GET", "POST" ]

    },

    "contents" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/contents?filter=place(https%3A%2F%2Fsandbox.jiveon.com%2Fapi%2Fcore%2Fv3%2Fplaces%2F3208)",

      "allowed" : [ "GET" ]

    },

    "self" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208",

      "allowed" : [ "DELETE", "PUT", "GET" ]

    },

    "places" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/places",

      "allowed" : [ "GET" ]

    },

    "avatar" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/avatar",

      "allowed" : [ "DELETE", "GET", "POST" ]

    },

    "blog" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3209",

      "allowed" : [ "DELETE", "PUT", "GET" ]

    },

    "announcements" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/announcements",

      "allowed" : [ "GET", "POST" ]

    },

    "categories" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/categories",

      "allowed" : [ "GET", "POST" ]

    },

    "html" : {

      "ref" : "https://sandbox.jiveon.com/groups/craig-example-group",

      "allowed" : [ "GET" ]

    },

    "followingIn" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/followingIn",

      "allowed" : [ "GET" ]

    },

    "activity" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/activities",

      "allowed" : [ "GET" ]

    },

    "members" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/members/places/3208",

      "allowed" : [ "GET", "POST" ]

    },

    "statics" : {

      "ref" : "https://sandbox.jiveon.com/api/core/v3/places/3208/statics",

      "allowed" : [ "GET", "POST" ]

    }

  },

  "id" : "1118"

}

 

A special note about the displayName field -- this is a value that will appear in the URI of the HTML page for the social group you are creating.  If you create a group through the Jive UI, it will manually compose this value based on the name that you type.  When using the API, you are responsible for composing a string that is acceptable as a path component, in addition to being unique for this Jive instance.

 

Let's take a look at several interesting fields in the newly created group:

  • memberCount is initialized to 1, because the requesting user is automatically made a member (actually an administrator) of the new group.  In general, API calls that create things mimic the default behaviors of the Jive UI, which does the same thing.
  • contentTypes lists all of the available content types in this Jive instance, because we did not specify a smaller list.  Note that cloud instances of Jive include the Ideation and Video plugins, so "ideas" and "videos" are included.
  • resources contains a series of URIs related to the new group, along with a list of allowed verbs that the calling user is allowed to utilize with that URI.  For example, a group administrator will be allowed to use DELETE or PUT on the URI of the group itself (to delete or update it respectively), but anyone else would only see GET as a valid option.  If you try to use one of the verbs that is not listed, you will receive a 403 ("Forbidden") error.
  • id contains an internal identifier for the new group.  Note that this is *not* the same identifying number that you see in the resource URIs.  You should treat this value as an internal implementation detail.  If you need to do something with this group later, use the URI that is returned in the self resource.

 

 

Coming Very Soon to a Cloud Release Near You

If you are a customer using Jive's cloud offering, then you will be able to use two new capabilities of the platform, group status updates and structured outcomes. Both of these will be available at the next update of the platform. Of course, you don't have to wait for it to be installed on prem for you to be able to use this. You can get developer credentials and start using sandbox.jiveon.com!

  • Group Status Updates
  • Structured outcomes

 

Wrapping up!

If you've got a cool example using the REST APIs, then I'd encourage you to add it to a document that one of our community members, LG . has created: REST API v3 Examples. Also, dalecox has a great document using .NET and Jive's REST API, REST API v3 .NET Examples. That's if for now. We covered the "fun" part, now, it's your turn for the "profit" part!

 

Enjoy & Happy Coding!

 

p.s. Thanks to Mark Weitzel for helping pull this blog together!

Filter Blog