Querying Office Delve Boards with JavaScript and REST
Posted
Sunday, January 11, 2015 8:41 PM
by
CoreyRoth
The new functionality of Office Delve, Boards, just came out recently. As a developer, you might be thinking how can I access this data in my own applications. This post will help you get started. These queries use the new Graph Query Language (GQL) syntax of Office Graph. As the GQL reference link points out you should be warned that these APIs are highly subject to change and should not be used in production applications. The queries we are using today were determined by examining the REST API calls from the pages inside Delve. They may work now, but they may not work in the future.
Querying the boards a user is following
First, we want to determine which boards a user is following. We want to return the same data that we see in the left navigation of Delve.
It appears Delve makes use of a new “protocol handler” like technology that has it’s own URL syntax. These URLs look like TAG://PUBLIC. To get the list of boards a user is following, we issue the following query:
TAG://PUBLIC/?NAME=*
However, we also have to include some Properties in our REST query to get the data we need. In particular interest is the new GQL action number 1050 that you use on the me actor. Here is what the entire REST query looks like. I recommend limiting the SelectProperties that you return. The important ones are Title, Path, and DocId.
https://<tenant>.sharepoint.com/_api/search/query?QueryText='Path:"TAG://PUBLIC/?NAME=*"'&Properties='IncludeExternalContent:true,GraphQuery:actor(me\,action\:1050),GraphRankingModel:action\:1050\,weight\:1\,edgeFunc\:time\,mergeFunc\:max'&SelectProperties='Title,Path,DocId'
Try typing it in the browser of your tenant.
Looking at the individual results, you’ll see the name of the board, it’s path and the DocId. The Title contains the name of the board in all caps. The Path we can use to query items that have been tagged. The DocId actually refers to an ActorId that we’ll use later.
Querying the items tagged to a board
When you visit a board’s page in Delve, it actually issues two queries to get the items that have been tagged to the board. First, it issues a query using the path we saw above. It does this to get the ActorId which is stored in the DocId property. It then uses that ActorId in a second query to get the actual items that have been tagged to the board. If you already know the ActorId, you can obviously skip the first step to retrieve it.
To get the ActorId, we issue a query using the path on the TAG URL with the name in all caps following the NAME parameter. This is just like what we saw in the results above. Here is what the REST query looks like. We are only interested in the DocId property so we specify that in the SelectProperties.
https://<tenant>.sharepoint.com/_api/search/query?QueryText='Path="TAG://PUBLIC/?NAME=<board name>"'&Properties='IncludeExternalContent:true'&SelectProperties='DocId'
Now let’s write some JavaScript code to retrieve this value. In my example, we’re going to retrieve the ActorId for the Marketing board in a SharePoint-hosted app. Make sure you request the Search permission in your AppManifest.xml. I have URL encoded the URL. This just uses a simple call with $.ajax. I’ve left out the use of deferreds to keep it simple.
$(document).ready(function () {
var queryUrl = _spPageContextInfo.webAbsoluteUrl + '/_api/search/query?' +
'QueryText=%27Path%3D"TAG%3A%2F%2FPUBLIC%2F%3FNAME%3DMARKETING"%27&Properties=%27IncludeExternalContent:true%27&SelectProperties=%27DocId%27';
$.ajax({ url: queryUrl, method: "GET", headers: { "Accept": "application/json; odata=verbose" }, success: onQuerySuccess, error: onQueryError });
});
In our onQuerySuccess function, we will retrieve the value of the ActorId. Remember it is stored in the DocId managed property. The data of search results is buried in multiple objects, so you have to go through quite a bit to get to it. For more information on querying search with JavaScript and REST, see this code sample on MSDN Code.
function onQuerySuccess(data) {
var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
var actorId;
$.each(results[0].Cells.results, function () {
if (this.Key == 'DocId')
actorId = this.Value;
});
$("#actorId").html(actorId);
}
Now, that we have the ActorId, we can issue the query to get the item associated with the board. In the simplest form, you issue a query with QueryText of * (everything). You then issue a GraphQuery using the ActorId and the undocumented ActionId of 1045. However, if you want the query to match exactly what is on the Board page, you need a few additional exclusions. These exclusions specifically remove content hidden from Delve as well as only show specific file extensions. Here is what the REST URL looks like.
https://<tenant>.sharepoint.com/_api/search/query?QueryText='* AND ((NOT HideFromDelve:True) AND (FileExtension:doc OR FileExtension:docx OR FileExtension:ppt OR FileExtension:pptx OR FileExtension:xls OR FileExtension:xlsx OR FileExtension:pdf OR ContentTypeId:0x010100F3754F12A9B6490D9622A01FE9D8F012*))'&Properties='GraphQuery:actor(<actorId>\,action\:1045),GraphRankingModel:action\:1045\,weight\:1\,edgeFunc\:time\,mergeFunc\:max,IncludeExternalContent:true'
When it comes to the JavaScript, we simply replace out the ActorId Again we encode the URL.
var boardQueryUrl = _spPageContextInfo.webAbsoluteUrl + '/_api/search/query?' +
"QueryText='* AND ((NOT HideFromDelve:True) AND " +
"(FileExtension:doc OR FileExtension:docx OR FileExtension:ppt OR FileExtension:pptx OR FileExtension:xls OR FileExtension:xlsx OR FileExtension:pdf OR ContentTypeId:0x010100F3754F12A9B6490D9622A01FE9D8F012*))'" +
"&Properties='GraphQuery:actor(" + actorId + "%5C%2Caction%5C%3A1045),GraphRankingModel%3Aaction%5C%3A1045%5C%2Cweight%5C%3A1%5C%2CedgeFunc%5C%3Atime%5C%2CmergeFunc%5C%3Amax,IncludeExternalContent:true'";
$.ajax({ url: boardQueryUrl, method: "GET", headers: { "Accept": "application/json; odata=verbose" }, success: onQuerySuccess2, error: onQueryError });
Now, in our success function, I simply return the results as a table by iterating through all of the rows and cells of the results. The first loop prints out the column names and the second one writes out each row.
function onQuerySuccess2(data) {
var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
$("#results").append('<table>');
$("#results").append('<tr>');
$.each(results[0].Cells.results, function () {
$("#results").append('<th>' + this.Key + '</th>');
});
$("#results").append('</tr>');
$.each(results, function () {
$("#results").append('<tr>');
$.each(this.Cells.results, function () {
$("#results").append('<td>' + this.Value + '</td>');
});
$("#results").append('</tr>');
});
$("#results").append('</table>');
}
Here’s what my results look like in my SharePoint-hosted app.
Comparing it to the original page in Delve for the boards, you will notice the results are the same.
If you are interested in developing with Boards in Office Delve, I hope you have found this post helpful. This information hasn’t really been documented so it’s highly subject to change. Try it out and let me know what you come up with.
Follow me on twitter: @coreyroth