Friday, 9 January 2015

Programmatically add a document to a Delve Board with REST

Microsoft recently launched the Boards feature in Delve, with which you can create Pinterest like boards and add content to them. You can add documents from your SharePoint sites as well as OneDrive for Business sites.  Here is a great introduction to the functionality: http://blogs.office.com/2015/01/07/introducing-boards-office-delve-new-way-organize-share-work/ 
I have been playing around a bit with this feature and have some interesting things to share. So Lets have a look at how this has been implemented under the hood.

1) The same Signals API which I have blogged about here is used in boards. AJAX requests are sent to the /_api/signalstore/signals endpoint when any operations are made in Delve (eg. add document to board)

2) Boards are internally referred to as "Tags". So when you add a document to a board, it gets "Tagged" with the name of the board. More on this later.

3) There seem to be 2 components in play. When you add a document to board, there is an "immediate" add in the front-end as well as a normal add when the incremental crawl adds the document in the Search Index. The front-end immediately  shows the user  that the document is added to a board. This is a very good solution as otherwise the user would have to wait till the incremental crawl has taken place.

Let us have a look at the API now. All the API is doing is adding/removing documents to boards and following/unfollowing boards. Unlike my previous post about modifying relationship signals in the Office Graph, with this API you will not be interfering with your Office Graph relationships so I think you can safely use this API in your solutions.  Now lets take a look at what actually happens under the hood:



There is a new button introduced in the document card. So when you click on "Add to Board" and select a board from the dropdown,  here is the JSON which is sent to the Signals API: 

(click to zoom)


Basically, it has 2 Important pieces of data: 

1) The document gets tagged with the name of the board. This tag is then used by Delve to search and get all documents belonging to a certain board. This is done by the first object with ActionType:Tag and Item Id as the absolute url of the document.

2) The current user is made to follow the Tag (which is the board name) so that it shows up on the left hand side in Delve. This is done by the second object with ActionType: Follow and Item Id: ‘Path=”TAG://PUBLIC/?NAME=MY+TEST+BOARD”  where the name of the board I selected was "My Test Board"

If you want to reproduce this exact behavior in your solution, here is the sample code you can start with. Please be aware that that this code only tags the document with the board name so that it is added to the search index and follows the board so that it appears in your boards in Delve. This does not do the front-end add to the board. So you will have to wait for an incremental crawl to run in Office 365 for the document to get added to the board and show up in Delve. I have observed this can take anywhere from 5 to 30 minutes. 

Here is the code:


The document will get added to the board:


Hope you enjoyed this post. I have plans to follow this up with some code samples which show how to remove documents from boards, unfollow boards and some other new functionality. Thanks for reading.

7 comments:

Unknown said...

Vardhaman,

Do you know why some O365 tenants might never show the tags posted using the _api/signalstore/signals api? For some O365 tenants we call our code against we see the tags for others the tags never appear. On those we receive a 200 OK response and no errors in the returning JSON object. But the tags never appear.

Any thoughts?

Vardhaman Deshpande said...

Hi Michael,

For the tenants which do not show the tags, what does the posted JSON look like when you add a tag in Delve? You can try and replicate that exactly.

Also, keep in mind that this API is not actively publicized by Microsoft so any changes to it will not be documented. It will be up to us to update our code.

Unknown said...

Vardhama,

The json object that is used against the tenants that work and the json that is used against the ones that don't work is the same. We are processing through a loop and tagging the same document in multiple tenants (the same document exists in all the tenants).

Unknown said...

Vardhaman,

Another question. When creating a Tag in the UI after the _api/signalstore/signals post there are a couple of posts to the url /_layouts/15/WsaUpload.ashx. Are those necessary? Didn't know if not making those calls might be part of my problem.

Vardhaman Deshpande said...

Hi Michael,

The WsaUpload.ashx calls are part of the Customer Experience Improvement Program. Have a look here http://www.wictorwilen.se/Post/About-the-Customer-Experience-Improvement-Program-in-SharePoint-2010.aspx

So I don't think that is required for the tags to show up.

Is one of your tenant on First Release mode? Does Delve work exactly the same on all the tenants? I am afraid I can only think of these things right now.

Unknown said...

Vardhaman,

Thanks for your ideas on this. We actually found it is an issue with some O365 tenants. The ones our code wouldn't work on we found that if you log in to O365 create a tag and then close the browser, open it and log back into the tenant the tag's were no longer there. We found this to be consistent behavior across all the tenants our code didn't work on.

Very odd.

Unknown said...

Hi Vardhaman,
The Delve post call's data is different for me and also the URL is different, however after I make a post call to the xxx/_api/signalstore/signals, I get a 200 message, but the document is not being added into the board even after 2 days. Is the api not working anymore? Or am I doing something wrong

POST call details made by Delve
URL:
https://XXX-my.sharepoint.com/_vti_bin/DelveApi.ashx/signals/batch
DATA:
[{"Type":"Tag","DocumentUrl":"https://XXX.sharepoint.com/personal/XXX.com/Documents/Presentation1.pptx","TagName":"My Board"},{"Type":"Follow","TagName":"TAG://PUBLIC/?NAME=MY+BOARD"}]
QUERY PARAMS:
flights=%27PulseWebStoryCards,PulseWebVideoCards,PulseWebFallbackCards,PulseWebContentTypesWave1,PulseWebContentTypeFilter%27

Response from xxx/_api/signalstore/signals
{
body:"{"d":{"signals":null}}",
contentType:"application/json;odata=verbose;charset=utf-8",
responseAvailable:true,
state:undefined,
statusCode:200,
statusText:"OK"
headers: ...
}