Category Archives: Office 365 – REST API

Getting all boards to which a document belongs using the Office Graph

If you use Delve in Office 365 (an extension of Office Graph), you should know what are boards, for logically classify your documents, without moving them to a new physical location (document libraries).

Like every services in Office 365, there’s an API to allow developers to create applications around Office 365. If you want more information about how to query the Office Graph in Office 365, you can refer to the following article at MSDN.

If you read the previous article, you will see that there’s no information in the API documentation, on how to know which boards a document belongs.

To achieve this goal, there’s an undocumented action (ID = 1046) you can use to query the Office Graph. This action is used such as the others :

ACTOR(<ActorId>,action:1046)

If you want to know what are the boards for a given document, the ActorId in the syntax above corresponds to the ID of the document. You can get the ID of a document by retrieving the DocId value from the search engine, by using a simple query or a graph query (e.g. for a document from the personal feed of the current user).

If you query the Office Graph with a syntax such as ACTOR(48202211,action:1046), you will get a search result such as below (it was truncated for focusing on the most important part):

Table = {
  Rows = (
    {
      Cells = (
        {
          Key = DocId,
          Value = 4362767297,
          ValueType = "Edm.Int64"
        },
        {
          Key = Path,
          Value = "TAG://PUBLIC/?NAME=FINANCE",
          ValueType = "Edm.String"
        },
        {
          Key = Title,
          Value = Finance,
          ValueType = "Edm.String"
        },
        {
          Key = Edges,
          Value = "[{\"ActorId\":48202211,\"ObjectId\":4362767297,\"Properties\":{\"Action\":1046,\"Blob\":[123,34,84,97,103,78,97,109,101,34,58,34,70,105,110,97,110,99,101,34,125],\"BlobContent\":\"{\\\"TagName\\\":\\\"Finance\\\"}\",\"ObjectSource\":1,\"Time\":\"2015-08-21T11:34:39.0000000Z\",\"Weight\":1}}]",
          ValueType = "Edm.String"
        }
      )
    },
    {
      Cells = (
        {
          Key = DocId,
          Value = 4362767298,
          ValueType = "Edm.Int64"
        },
        {
          Key = Path,
          Value = "TAG://PUBLIC/?NAME=MARKETING+STRATEGY",
          ValueType = "Edm.String"
        },
        {
          Key = Title,
          Value = "Marketing Strategy",
          ValueType = "Edm.String"
        },
        {
          Key = Edges,
          Value = "[{\"ActorId\":48202211,\"ObjectId\":4362767298,\"Properties\":{\"Action\":1046,\"Blob\":[123,34,84,97,103,78,97,109,101,34,58,34,77,97,114,107,101,116,105,110,103,32,83,116,114,97,116,101,103,121,34,125],\"BlobContent\":\"{\\\"TagName\\\":\\\"Marketing Strategy\\\"}\",\"ObjectSource\":1,\"Time\":\"2015-08-21T11:19:06.0000000Z\",\"Weight\":1}}]",
          ValueType = "Edm.String"
          }
        }
      )
    }
  )
}

The search result above indicates that our document (ActorId = 48202211) was added in two boards called “Finance” and “Marketing Strategy“. Each row in the search result corresponds to a board with its properties (retrieved from those that have been specified in the search query).

Getting boards for multiple documents within the same request

As we have seen, it’s pretty simple to retrieve the boards for a single document but what should I do if I want to retrieve the boards for many documents ?

For performance issue it’s not viable to execute a request for each document. So what’s the solution ?

Office Graph lets you to combine many actors in the same request. So if you execute a request such as the one below (each actor corresponds to a document), you will get as response, a search result with the boards for each document.

OR(ACTOR(48204878,action:1046),ACTOR(48204877,action:1046),ACTOR(48202211,action:1046))

Good, but how can I know which document is associated to which board ?

If you paid attention to the search result, there’s a property called “Edges” for each row. The value of this property is a JSON string that has been serialized.

If we deserialize and format those values, they look like this:

Edges for row #1
[
  {"ActorId":48204878,"ObjectId":4362767297,"Properties":{"Action":1046,"Blob":[123,34,84,97,103,78,97,109,101,34,58,34,70,105,110,97,110,99,101,34,125],"BlobContent":"{\"TagName\":\"Finance\"}","ObjectSource":1,"Time":"2015-08-21T11:18:52.0000000Z","Weight":1}},
  {"ActorId":48202211,"ObjectId":4362767297,"Properties":{"Action":1046,"Blob":[123,34,84,97,103,78,97,109,101,34,58,34,70,105,110,97,110,99,101,34,125],"BlobContent":"{\"TagName\":\"Finance\"}","ObjectSource":1,"Time":"2015-08-21T11:34:39.0000000Z","Weight":1}},
  {"ActorId":48204877,"ObjectId":4362767297,"Properties":{"Action":1046,"Blob":[123,34,84,97,103,78,97,109,101,34,58,34,70,105,110,97,110,99,101,34,125],"BlobContent":"{\"TagName\":\"Finance\"}","ObjectSource":1,"Time":"2015-08-21T20:50:40.0000000Z","Weight":1}}
]

Edges for row #2
[
 {"ActorId":48204877,"ObjectId":4362767298,"Properties":{"Action":1046,"Blob":[123,34,84,97,103,78,97,109,101,34,58,34,77,97,114,107,101,116,105,110,103,32,83,116,114,97,116,101,103,121,34,125],"BlobContent":"{\"TagName\":\"Marketing Strategy\"}","ObjectSource":1,"Time":"2015-08-21T20:50:35.0000000Z","Weight":1}},
 {"ActorId":48202211,"ObjectId":4362767298,"Properties":{"Action":1046,"Blob":[123,34,84,97,103,78,97,109,101,34,58,34,77,97,114,107,101,116,105,110,103,32,83,116,114,97,116,101,103,121,34,125],"BlobContent":"{\"TagName\":\"Marketing Strategy\"}","ObjectSource":1,"Time":"2015-08-21T11:19:06.0000000Z","Weight":1}}
]

As you can see, it’s an array in which each object corresponds to an actor with some properties.

The important values for each object corresponds to :

  • ActorId ==> The ID of our document
  • ObjectId ==> The ID of the board
  • TagName ==> The name of the board
  • Time ==> When the document was added to the board

In this example in which we queried the Office Graph for three documents, two of them (ActorId = 48204877 and ActorId = 48202211) were added in two boards (“Finance” and “Marketing Strategy“). The third document (ActorId = 48204878) was only added in the “Finance” board.

Advertisements

Create time-limited share link for a SharePoint document using REST API

If you use SharePoint to store your documents, you necessarily needed one day to share a document with an external user to your organization.

SharePoint, like other solutions such as OneDrive, DropBox, Box, GoogleDocs… gives you the capability to generate guest links on files stored in document libraries.

To be able to generate those kind of links, you must enable the correct option at the tenant level as you can see on the screenshot below.

External Sharing - Settings

When the option is enabled, you generate the link from the share dialog box on a document.

External Sharing - Guest Link

It’s very useful but as you can see, there’s no option to limit the time for which the link is available. When you want to disable the link, you have to go back to the dialog box of the document an select the “Disable” option. If you do this on hundreds or thousands of documents, it will be unmanageable very fast.

REST API to our rescue

Fortunately, as developers, there’s often a solution that we can use to cover our needs.

In our case, if you look into the REST API (but it’s also available with CSOM), on a SP.File object, there’s a method called GetPreAuthorizedAccessUrl which allows you to generate a time-limited link.

There’s many possibilities to get a SP.File object to then call the method, so let’s take an example using the GetFileByServerRelativeUrl from an SP.Web :

https://tenant.sharepoint.com/_api/Web/GetFileByServerRelativeUrl('/Shared%20Documents/2013%20Contoso%20products.pdf')/GetPreAuthorizedAccessUrl(24)

As you can see above, we retrieve the SP.File object associated to a file stored in a library, then we generate the link which will be available for one day (24 hours). The response returned by the server is something like :

https://tenant.sharepoint.com/_layouts/15/download.aspx?guestaccesstoken=lsRrsejmU9HlzY0Kw87A9NFu4yeDgMPusDBGF%2frz6AU%3d&docid=0588b11e4a047423e8667ee0ed9d67bf9&expiration=8%2f18%2f2015+9%3a14%3a34+AM&userid=28&authurl=True

Now that you have a link which doesn’t require authentication to access/download the file, you just have to send it to your external users.

After one day, if they try to use the same link, they will receive an error message.

As we have seen in this article, SharePoint has all necessary things to generate time-limited links to share documents.

Unfortunately, there’s no option (at this time) in the UI to use this capability, so it’s up to you to develop it. 😦

Determine which languages are activated on a SharePoint site with REST API

If you develop mobile applications which need to be multilingual, it will happen sooner or later that you wanted to know which languages are activated on your SharePoint sites.

To retrieve information about your SharePoint sites, your first instinct will be to use the REST API. To achieve this goal you typically call URLs such as :

https://contoso.sharepoint.com/_api/Web
https://contoso.sharepoint.com/sites/HR/_api/Web

By default when you call those URLs, not all properties available for the site are returned in the server response. Only a subset (called the default scalar property set) is included in the response as you can see in the sample below :

{
    AllowRssFeeds = 1;
    AlternateCssUrl = "";
    AppInstanceId = "00000000-0000-0000-0000-000000000000";
    Configuration = 0;
    Created = "2015-06-05T15:12:37.89";
    CustomMasterUrl = "/_catalogs/masterpage/seattle.master";
    Description = "A new description for the Contoso Team Site";
    DocumentLibraryCalloutOfficeWebAppPreviewersDisabled = 0;
    EnableMinimalDownload = 1;
    Id = "7e75f9bc-db75-4425-b934-86bdf913f9c5";
    IsMultilingual = 1;
    Language = 1033;
    LastItemModifiedDate = "2015-08-05T17:11:31Z";
    MasterUrl = "/_catalogs/masterpage/seattle.master";
    OverwriteTranslationsOnChange = 0;
    QuickLaunchEnabled = 1;
    RecycleBinEnabled = 1;
    ServerRelativeUrl = "/";
    SiteLogoUrl = "<null>";
    SyndicationEnabled = 1;
    Title = "Contoso Team Site";
    TreeViewEnabled = 0;
    UIVersion = 15;
    UIVersionConfigurationEnabled = 0;
    Url = "https://contoso.sharepoint.com";
    WebTemplate = STS;
    "odata.editLink" = Web;
    "odata.id" = "https://contoso.sharepoint.com/_api/Web";
    "odata.metadata" = "https://contoso.sharepoint.com/_api/$metadata#SP.ApiData.Webs/@Element";
    "odata.type" = "SP.Web";
}

As you can see in the default scalar property set, we are able to know if the current site is multilingual or not (IsMultilingual = 1), but we don’t know which languages have been activated.

To retrieve the value we want, we need to modify our call to the REST API so that we have to include additional parameters in the querystring to specify which properties must be included in the server response.

https://contoso.sharepoint.com/_api/Web?$select=Title,Url,IsMultilingual,SupportedUILanguageIds

When we execute that request, the server return the following response, and we now are able to know which languages (SupportedUILanguageIds) are used by our SharePoint site.

{
    IsMultilingual = 1;
    SupportedUILanguageIds =     (
        1033,
        1036
    );
    Title = "Contoso Team Site";
    Url = "https://contoso.sharepoint.com";
    "odata.editLink" = Web;
    "odata.id" = "https://contoso.sharepoint.com/_api/Web";
    "odata.metadata" = "https://contoso.sharepoint.com/_api/$metadata#SP.ApiData.Webs/@Element&$select=Title,Url,IsMultilingual,SupportedUILanguageIds";
    "odata.type" = "SP.Web";
}

Note that although it’s very useful to be able to select which properties will be included in the server response, if you want to include all the default properties plus a new one (SupportedUILanguageIds in our case), you have to put the entire list in the querystring.

Many types in SharePoint REST API doesn’t include all available properties in their default scalar property set. If you need to know which properties are included and which are not, you can refer to the documentation (e.g. https://msdn.microsoft.com/en-us/library/dd928431%28v=office.12%29.aspx).

Generate thumbnail of a document stored in SharePoint from its URL

In a previous article, we have seen how to generate a document thumbnail from its metadata (siteId, webId, uniqueId, docId…) retrieved from the search engine.

With these metadata, you just have to build and call an URL such as the following :

https://tenant.sharepoint.com/_layouts/15/getpreview.ashx?guidFile=<GUID>&guidSite=<GUID>&guidWeb=<GUID>&docid=<Int>&metadatatoken=<String>

Although easy to implement, this solution is not convenient every time, especially when you don’t use the search engine to retrieve data.

For example, when you use the Video REST API or the SharePoint REST API to manipulate list items, you don’t retrieve some of the required properties to generate the preview as described in our previous article.

One solution should be to query the search engine for the associated file to retrieve required metadata, then build and call the URL to generate the preview. This solution works very well but it’s pretty inefficient because you have to make 2 requests for each thumbnail.

A better solution based on the same HTTP Handler

Last week, I was working on different things around Office 365 and I discovered a better solution based on the same HTTP Handler.

It’s possible, rather than passing many parameters (siteId, webId, docId…), to pass only one parameter called ‘path’.

This parameter expects a value equal to the URL of the document/file for which you want to generate a thumbnail. To generate a preview, the URL should look like this :

https://tenant.sharepoint.com/portals/hub/_layouts/15/getpreview.ashx?path=https%3A%2F%2Ftenant.sharepoint.com%2Fportals%2Fcommunity%2FpVid%2FBiking%2520to%2520Work.mp4

In the sample above which generates a thumbnail for a video stored in an Office 365 video channel), you just have to encode the path of the file, and add it to the querystring for the ‘path‘ parameter.

I have tested with many file types (Word, Excel, PowerPoint, MP4…), stored in different containers (document libraries, video channels…) and it works for each of them.

For information, this solution is used by Delve to generate thumbnails for video files stored in Office 365 Video 😉

Delve - HomePage

Search videos using the Office 365 Video REST API

Office 365 is an awesome solution to share videos in a dedicated portal, organized in different channels. Channels are used (for example) to split videos by themes or categories.

But if you create a lot of channels in your organization or if you have a lot of videos in each channel, it may be pretty difficult to find relevant videos.

If you want to create an application on top of Office 365 Video, it’s interesting to know that the REST API exposes capabilities to search videos, globally at the service level, or at the channel level.

Build and submit search queries

When you want to use the Office 365 Video REST API, you have to submit requests to the endpoint which is only accessible through the portal URL as you can see below.

https://tenant.sharepoint.com/portals/hub/_api/VideoService

As we previously said, this endpoint exposes search capabilities at two different levels :

  • Video Service (across all channels)
  • Channel

Depending on which level you want to search videos, you have to build requests by appending path components as you can see below :

Across all channels

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Search/Query

On a specific channel

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Search/Query

Add parameters to the querystring to specify search criterias

To retrieve only information that you want, you have to add some parameters to the querystring. Three possibilites are offered to you :

  • querytext
  • startItemIndex
  • itemLimit

As you can imagine, the most important parameter is querytext which allows you to make fulltext searches. startItemIndex and itemLimit are used to perform paging operations.

For example if you want to search the first 10 videos which contains the ‘Awesome’ word, across all channels, your request should look something like that :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Search/Query?querytext='Awesome'&itemLimit=10

In the same manner, if you want to retrieve the same videos on a specific channel, your query should look something like that :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Search/Query?querytext='Awesome'&itemLimit=10

By querying those URLs, you will retrieve a list of videos. Each video is described by the following structure :

<entry>
<id>https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')</id>
<category term="SP.Publishing.VideoItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Author" type="application/atom+xml;type=entry" title="Author" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/Author" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Owner" type="application/atom+xml;type=entry" title="Owner" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/Owner" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/PeopleInMedia" type="application/atom+xml;type=feed" title="PeopleInMedia" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/PeopleInMedia" />
<title />
<updated>2015-01-01T01:00:00Z</updated>
<author>
  <name />
</author>
<content type="application/xml">
  <m:properties>
    <d:ChannelID m:type="Edm.Guid">01234567-abcd-cded-1234-1234567890ab</d:ChannelID>
    <d:CreatedDate m:type="Edm.DateTime">2015-01-01T01:00:00Z</d:CreatedDate>
    <d:Description />
    <d:DisplayFormUrl>https://tenant.sharepoint.com/portals/community/pVid/Forms/DispForm.aspx?ID=1</d:DisplayFormUrl>
    <d:FileName>AwesomeVideo.mp4</d:FileName>
    <d:OwnerName>Stephane Cordonnier</d:OwnerName>
    <d:ServerRelativeUrl>/portals/community/pVid/AwesomeVideo.mp4</d:ServerRelativeUrl>
    <d:ThumbnailUrl>https://tenant.sharepoint.com/portals/community/pVid/AwesomeVideo.mp4.PNG?VideoPreview=1</d:ThumbnailUrl>
    <d:Title>My Awesome Video</d:Title>
    <d:ID m:type="Edm.Guid">01234567-abcd-cded-1234-1234567890ab</d:ID>
    <d:Url>https://tenant.sharepoint.com/portals/community/pVid/AwesomeVideo.mp4</d:Url>
    <d:VideoDurationInSeconds m:type="Edm.Int32">120</d:VideoDurationInSeconds>
    <d:VideoProcessingStatus m:type="Edm.Int32">2</d:VideoProcessingStatus>
    <d:ViewCount m:type="Edm.Int32">10</d:ViewCount>
    <d:YammerObjectUrl>https://tenant.sharepoint.com/portals/hub/_layouts/15/videoplayer.aspx?v=https%3A%2F%2Ftenant%2Esharepoint%2Ecom%2Fportals%2Fcommunity%2FpVid%2FAwesomeVideo%2Emp4</d:YammerObjectUrl>
  </m:properties>
</content>
</entry>

Retrieve popular videos across all channels, or for a specific channel

It’s great to be able to search for videos but if you use the web version of Office 365 Video, you probably saw that the homepage displays popular videos. I guess you wonder how to retrieve those videos ?

The search endpoint mentioned above has special syntax to get those data. If you want to retrieve popular videos globally or for a specific channel, you have to submit requests using the following URLs:

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Search/Popular
https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Search/Popular

As for simple searches, you can use startItemIndex and itemLimit to perform paging through popular videos.

If you want more information on the Office 365 Video REST API, you can read the official documentation on the MSDN website : https://msdn.microsoft.com/office/office365/APi/video-rest-operations.

AADSTS90093 – Calling principal cannot consent due to lack of permissions

When you develop your own applications which use the Office 365 REST API, it might happen that users are facing the following error message when they try to authenticate, when your application is supposed to ask the consent of the user to access his data.

AADSTS90093 - Authentication Error

The difficult thing to understand is why this message is displayed and why all users are not concerned ?

Declare the application’s rights in Azure AD

When you create an application, you have to declare which rights are needed to access data when you make calls to the REST API.

Those rights are declared in Azure AD through the web console (https://manage.windowsazure.com) as you can see below.

Azure Manage Portal - Application Permissions

Which is not indicated in the web console is that some of those rights need that an administrator (at the tenant level) give a consent to allow your application to use them.

If the consent of an administrator was not given and a non-administrator user tries to use the application, he will receive the following error message : AADSTS90093 – Calling principal cannot consent due to lack of permissions.

What permissions require an administrator consent ?

If you would like a complete description of how permissions work on Office 365, you could refer to the official documentation on MSDN : https://msdn.microsoft.com/office/office365/HowTo/application-manifest

In short if you want to know what permissions require an administrator consent, it depends of which product  and which features you want to use.

You can find below a quick summary (grouped by products) of all the permissions which require an administrator consent. All other permissions (not listed below) only require a user consent.

SharePoint

  • Have full control of all site collections
  • Run search queries as a user
  • Read user profiles
  • Read and write user profiles
  • Read managed metadata
  • Read and write managed metadata

Outlook

No permission requires an administrator consent

Azure Active Directory

  • Read all users’ full profiles
  • Read directory data (except if the application is registered in the same tenant as the user)
  • Read and write directory data
  • Access the directory as the signed-in user (only for web applications)

Yammer

No permission requires an administrator consent

What to do if I encounter the error message ?

If you are facing to the error message mentioned previously, the first thing to do is to check if your application uses one of the permission in the list above.

If it’s the case, make sure that you absolutely need it, otherwise remove the right from the declared permissions for your application in Azure AD and it should solve the problem.

For example, you can perform searches on SharePoint sites under the identity of the current user, even if you only have the “Read items in all site collection” permission. It’s not needed to add the “Run search queries as a user” permission.

If you need the permission, you have to ask a tenant administrator to consent your application. Until the administrator consent, all users which are not administrators of the Office 365 tenant won’t be able to log-in and use your application.

Introducing the new Office 365 unified API

Build conference was held in San Francisco this week (from April 29th to May 1st) and it was the place to be because Microsoft made a lot of announcements around its ecosystem (Windows 10, Azure, HoloLens, Office 365…).

Among all the news annouced this week, we particularly appreciated the launch (in preview version for now) of the Office 365 unified API. Let’s take a look to this new API.

Why a new API ?

As you probably know, Office 365 offers a lot of features for companies who needs a directory, emails, instant messaging, collaboration, videos, search, social network…

Each of these features are offered by a dedicated product (Azure AD, Exchange, Lync, SharePoint, Yammer, OneDrive for Business…) and it was pretty complicated to develop solutions which are connected with all of them.

Indeed, each product has its own API, accessible through a dedicated endpoint :

It’s to simplify all of this, that the new Office 365 Unified API was created. It allows developers to create solutions which are able to reach the content of each product from a single endpoint.

Office365 Unified API

A single endpoint is more easy to use and it simplifies a lot of tasks such as managing authentication tokens (you need one access token for each endpoint when you use the actual Office 365 APIs).

This new API works like the actual APIs so to use it, you need to :

  • Register you app in Azure AD
  • Define permission scopes and security
  • Authenticate through OAuth 2.0

Office365 Unified API - Registration in Azure

To retrieve data from your tenant and after successful completion of the authentication process, you can send requests to the endpoint as you can see in the following examples.

Me (or other users)

Get information about the current user (the authenticated user) :

https://graph.microsoft.com/beta/me

Get the picture (of given dimensions) for the current user :

https://graph.microsoft.com/beta/me/userphotos/96X77

Get the manager, the subordinates or the groups for the current user :

https://graph.microsoft.com/beta/me/manager
https://graph.microsoft.com/beta/me/directReports
https://graph.microsoft.com/beta/me/memberOf

Get information about another user in your company’s directory  :

https://graph.microsoft.com/beta/contoso.com/users/demo@contoso.com
https://graph.microsoft.com/beta/contoso.com/users/demo@contoso.com/manager
https://graph.microsoft.com/beta/contoso.com/users/demo@contoso.com/memberOf

Messages

Get the email messages for the current user :

https://graph.microsoft.com/beta/me/messages

Get the last 5 message for the current user :

https://graph.microsoft.com/beta/me/messages?$top=5

Get the next 5 messages ordered by creation date :

https://graph.microsoft.com/beta/me/messages?$top=5&$skip=5&$orderby=DateTimeCreated

Calendar / Events

Get the events for the current user :

https://graph.microsoft.com/beta/me/events

Get the events for the current user between the start date and the end date:

https://graph.microsoft.com/beta/me/calendarview?startdatetime=2015-04-01t01:00:00z&enddatetime=2015-04-16t23:00:00z

SharePoint Files / OneDrive Files

Get OneDrive’s for Business files for the current user and get a specific file by using its ID :

https://graph.microsoft.com/beta/me/files
https://graph.microsoft.com/beta/me/files/<id>

Get OneDrive’s for Business files for a given user :

https://graph.microsoft.com/beta/demo@contoso.com/files

Groups

Get the groups (collaboration and not security/distribution) for your company :

https://graph.microsoft.com/beta/contoso.com/groups?$filter=groupType+eq+'Unified'

Get the members, the files, and the conversations for a group by using its ID :

https://graph.microsoft.com/beta/contoso.com/groups/<id>/members
https://graph.microsoft.com/beta/contoso.com/groups/<id>/files
https://graph.microsoft.com/beta/contoso.com/groups/<id>/conversations

Office Graph / Delve

Get the people with whom the current user work with :

https://graph.microsoft.com/beta/me/workingWith

Get the data (documents, email attachments…) which are trending around the current user :

https://graph.microsoft.com/beta/me/trendingAround

What’s coming next ?

In the examples presented in this article, we only saw how to get data but you are already able to perform CRUD operations as you can do it today with other dedicated endpoints.

It’s also good to note that Microsoft has updated its client libraries for .NET, iOS and Android to support the new unified API.

The Office 365 Unified API available today is just the first version (a preview version) and a lot of improvements will be available in the future. New data types will be added in the next few months.

Among some of the improvements already announced by Microsoft during the conference :

  • Tasks
  • Notes
  • Skype
  • Personal Contacts
  • Notifications
  • And much more…

Want to learn more and want to try it ?

The first thing to see if you want to discover the new API (this article was based on it) is the webcast of the session named “Supercharging Your Custom Solutions with the Office 365 Unified API Endpoint” which has been recorded during the Build conference. It’s available on Channel 9 : http://channel9.msdn.com/Events/Build/2015/3-641

If you want to learn more about the new Office 365 Unified API, you can also refer to the official documentation available at http://dev.office.com/unifiedAPIs.

Microsoft has also created/updated some websites if you want to try the new API directly from your web browser:

Office 365 Video REST API Overview

On April 16th, Office 365 Video has started moving from first release to general availability worldwide.

At the same time, a new REST API was launched and documented to be able to build your own applications (mobile, desktop, web…) on top of Office 365 Video.

Let’s get started to learn how to use this new API to perform basic operations.

Check if Office 365 Video is available and discover the API endpoint

Because Office 365 video has started to be deployed on all tenants few days ago, it’s not necessary available for your organization and/or your Office 365 administrator can disable it.

To check if the service is currently available and/or usable, you can send a request to the following URL :

https://tenant.sharepoint.com/_api/VideoService.Discover

By querying this URL, you will retrieve a response as you can see below :

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xml:base="https://tenant.sharepoint.com/_api/">
<id>https://tenant.sharepoint.com/_api/VideoService.Discover</id>
<category term="SP.Publishing.VideoServiceDiscoverer" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="VideoService.Discover" />
<title />
<updated>2015-01-01T01:00:00Z</updated>
<author>
  <name />
</author>
<content type="application/xml">
  <m:properties>
    <d:ChannelUrlTemplate>https://tenant.sharepoint.com/portals/hub/_layouts/15/videochannel.aspx?channel={0}</d:ChannelUrlTemplate>
    <d:IsVideoPortalEnabled m:type="Edm.Boolean">true</d:IsVideoPortalEnabled>
    <d:PlayerUrlTemplate>https://tenant.sharepoint.com/portals/hub/_layouts/15/videoplayer.aspx?v={0}</d:PlayerUrlTemplate>
    <d:VideoPortalLayoutsUrl>https://tenant.sharepoint.com/portals/hub/_layouts/15</d:VideoPortalLayoutsUrl>
    <d:VideoPortalUrl>https://tenant.sharepoint.com/portals/hub</d:VideoPortalUrl>
  </m:properties>
</content>
</entry>

In this response, you can check if Office 365 video is available and activated (cf. IsVideoPortalEnabled).

If the service is available, you can retrieve the VideoPortalUrl which is the path used by the new REST API to get the list of channels, get a video, upload a video, etc…

Retrieve the list of available channels

In Office 365 Video, when a user wants to upload a video and share it with colleagues, the video is stored (classified) in a channel.

By default, channels are created by administrators and viewable by all the users. To retrieve the list of all available (viewable) channels, you have to query the VideoPortalUrl retrieved previously as you can see below :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels

By querying that URL, you will retrieve a list of channels. Each channel is described by the following structure :

<entry>
<id>https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')</id>
<category term="SP.Publishing.VideoChannel" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Search" type="application/atom+xml;type=entry" title="Search" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Search" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SpotlightVideos" type="application/atom+xml;type=feed" title="SpotlightVideos" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/SpotlightVideos" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Videos" type="application/atom+xml;type=feed" title="Videos" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos" />
<title />
<updated>2015-01-01T01:00:00Z</updated>
<author>
  <name />
</author>
<content type="application/xml">
  <m:properties>
    <d:Description />
    <d:Id m:type="Edm.Guid">01234567-abcd-cded-1234-1234567890ab</d:Id>
    <d:TileHtmlColor>#2A8DD4</d:TileHtmlColor>
    <d:Title>Community</d:Title>
    <d:YammerEnabled m:type="Edm.Boolean">true</d:YammerEnabled>
  </m:properties>
</content>
</entry>

 

If you want to retrieve the list of channels on which you are able to perform edit operations (e.g upload, update, delete), you just need to query the following URL (the structure of the response if the same as for viewable channels) :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/CanEditChannels

Retrieve the list of videos for a channel

Now that you’re able to get the list of channels, you certainly want to retrieve the list of available videos for that channel.

It’s pretty simple and you just have to query that URL (replace the GUID with the appropriate value based on IDs retrieved in the list of channels) :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos

By querying that URL, you will retrieve a list of videos for the selected channel. Each video is described by the following structure :

<entry>
<id>https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')</id>
<category term="SP.Publishing.VideoItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Author" type="application/atom+xml;type=entry" title="Author" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/Author" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Owner" type="application/atom+xml;type=entry" title="Owner" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/Owner" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/PeopleInMedia" type="application/atom+xml;type=feed" title="PeopleInMedia" href="VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/PeopleInMedia" />
<title />
<updated>2015-01-01T01:00:00Z</updated>
<author>
  <name />
</author>
<content type="application/xml">
  <m:properties>
    <d:ChannelID m:type="Edm.Guid">01234567-abcd-cded-1234-1234567890ab</d:ChannelID>
    <d:CreatedDate m:type="Edm.DateTime">2015-01-01T01:00:00Z</d:CreatedDate>
    <d:Description />
    <d:DisplayFormUrl>https://tenant.sharepoint.com/portals/community/pVid/Forms/DispForm.aspx?ID=1</d:DisplayFormUrl>
    <d:FileName>AwesomeVideo.mp4</d:FileName>
    <d:OwnerName>Stephane Cordonnier</d:OwnerName>
    <d:ServerRelativeUrl>/portals/community/pVid/AwesomeVideo.mp4</d:ServerRelativeUrl>
    <d:ThumbnailUrl>https://tenant.sharepoint.com/portals/community/pVid/AwesomeVideo.mp4.PNG?VideoPreview=1</d:ThumbnailUrl>
    <d:Title>My Awesome Video</d:Title>
    <d:ID m:type="Edm.Guid">01234567-abcd-cded-1234-1234567890ab</d:ID>
    <d:Url>https://tenant.sharepoint.com/portals/community/pVid/AwesomeVideo.mp4</d:Url>
    <d:VideoDurationInSeconds m:type="Edm.Int32">120</d:VideoDurationInSeconds>
    <d:VideoProcessingStatus m:type="Edm.Int32">2</d:VideoProcessingStatus>
    <d:ViewCount m:type="Edm.Int32">10</d:ViewCount>
    <d:YammerObjectUrl>https://tenant.sharepoint.com/portals/hub/_layouts/15/videoplayer.aspx?v=https%3A%2F%2Ftenant%2Esharepoint%2Ecom%2Fportals%2Fcommunity%2FpVid%2FAwesomeVideo%2Emp4</d:YammerObjectUrl>
  </m:properties>
</content>
</entry>

 

As you can see above, you are able to retrieve a lot of information about the video (title, author, duration, number of views, URL…).

But if you watch the URL value, it corresponds to the physical location of the video stored in a SharePoint site (each channel is a SharePoint site collection).

If a lot of users try to access the video at the same time, it may have an impact of the performance of your tenant because SharePoint is not optimized for that kind of usage.

When a video is uploaded in a channel, it’s also sent to Azure Media Services (at no additionnal costs) to be able to use the streaming capabilities of Azure.

If you want to retrieve the corresponding URL of your video in Azure Media Services, you just need to query the following URL (replace the GUIDs for the channel and the video with appropriate values) :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/GetPlaybackUrl(0)

At the end of the URL, you can see a value when calling the GetPlaybackUrl method. When the value is equal to zero, it indicates you want to use the HTTP Live Streaming (HLS) capability of Azure Media Services.

HLS is compatible with all devices (mobile, desktop, web…) but if you want to use another format/protocol, you can pass ‘1’ for the value, which indicates you want to use Smooth Streaming/MPEG-DASH instead of HLS. See the example below :

https://tenant.sharepoint.com/portals/hub/_api/VideoService/Channels(guid'01234567-abcd-cded-1234-1234567890ab')/Videos(guid'01234567-abcd-cded-1234-1234567890ab')/GetPlaybackUrl(1)

For security reasons, videos stored in Azure Media Services are encrypted so if you want to use Smooth Streaming/MPEG-DASH instead of HLS, you need one additionnal step (retrieve an access token) to be able to use and access the retrieved URL.

Conclusion

We’ve just give you an overview of how to access and use the new REST API available with Office 365 Video to retrieve channels and videos but many other operations are available in this API (upload videos, delete videos, update metadata…).

The new API is already used by the Office 365 Video application for iPhone : https://itunes.apple.com/app/id953685679

If you want more information on the Office 365 Video REST API, you can read the documentation on the MSDN website : https://msdn.microsoft.com/office/office365/APi/video-rest-operations.

How to disable Office Graph and what are the impacts on the REST API

On March 16th, Delve (based on Office Graph) has started rolling out to eligible Office 365 business customers worldwide.

This is a great news for all the users who wants a new way to discover and work with their documents stored in their Office 365 tenant.

But because it’s a brand new way to work, all customers doesn’t necessarily want to offer Delve to all their users for now.

Disable Office Graph on the Office 365 tenant

If you don’t want to use Office Graph in your company, it’s possible to disable it for all the users.

To do it and as a tenant administrator, you have to connect to the SharePoint Admin Center then go the “Settings” section.

In this screen, you just need to check “Don’t allow access to the Office Graph” as you can see in the screenshot below.

Disable Office Graph

Then save your modification and after a short time (from few seconds to few minutes), Delve and Office Graph will be disabled/unusable for all the users of your Office 365 tenant.

Querying the Office Graph with the REST API

Now that we are able to enable/disable the Office Graph at the tenant level, let see how to query it by using the REST API and what happens when the feature was disabled.

For now (Microsoft is working to offer new possibilities/APIs in the future), you have to use the SharePoint search API to query the Office Graph. It’s pretty simple and there’s two different ways to achieve this goal.

My favorite is to POST the query to the search endpoint. The endpoint is accessible from all the SharePoint sites on your tenant.

https://<tenant>.sharepoint.com/_api/search/postquery/
OR
https://<tenant>.sharepoint.com/sites/anotherSiteCollection/_api/search/postquery/

Office Graph queries can be very simple or much more complicated to write, depending on what you want to retrieve. Below, you can see a sample which retrieves the documents (Word, Excel, PowerPoint, PDF and Office 365 Videos) as you can see when you display Delve’s homepage.

{
  "request": {
    "Properties": [
      {
        "Name": "GraphQuery",
        "Value": {
          "QueryPropertyValueTypeIndex": 1,
          "StrVal": "AND(ACTOR(ME,action:1021),ACTOR(ME,OR(action:1021,action:1036,action:1037,action:1039,action:1052)))"
        }
      },
      {
        "Name": "GraphRankingModel",
        "Value": {
          "QueryPropertyValueTypeIndex": 1,
          "StrVal": "action:1021,weight:1,edgeFunc:weight,mergeFunc:max"
        }
      }
    ],
    "QueryTemplate": "({searchterms}) AND ((NOT HideFromDelve:True) AND (FileExtension:doc OR FileExtension:docx OR FileExtension:xls OR FileExtension:xlsx OR FileExtension:ppt OR FileExtension:pptx OR FileExtension:one OR FileExtension:pdf OR ContentTypeId:0x010100F3754F12A9B6490D9622A01FE9D8F012*))",
    "Querytext": "*",
    "RankingModelId": "0c77ded8-c3ef-466d-929d-905670ea1d72",
    "RowLimit": 20,
    "StartRow": 0,
    "Timeout": 30000,
    "TrimDuplicates": true
  }
}

If you want more information about how to build an Office Graph query, please refer to the following MSDN article : https://msdn.microsoft.com/en-us/office/office365/howto/query-Office-graph-using-gql-with-search-rest-api

Execute a query when the Office Graph was disabled

You probably ask yourself : what will happen if we execute the previous query on a tenant from which the Office Graph was disabled ?

As for a lot of things when you use the Office 365 REST API, if you try to use an unavailable feature or if you send malformed data, an exception is thrown and returned to the user.

The Office Graph and the SharePoint search engine work as well. If you try to execute an Office Graph query when the feature is disabled, an exception is thrown. You can see below an example of the server response.

{
  "odata.error": {
    "code": "-1, Microsoft.Office.Server.Search.REST.SearchServiceException",
    "message": {
      "lang": "en-US",
      "value": "Graph queries currently disabled."
    }
  }
}

For now, there’s no REST API to check if the Office Graph feature is enabled or disabled. The only way to check is to execute a query and catch the exception.

Retrieve available web templates and create a subsite with Office 365 REST API

When you work with the Office 365 REST API, especially with SharePoint parts of the API, you will probably need at a given time, to create subsites in a site collection.

If you don’t know how to achieve this goal, we will explain in this article how to do it.

How to create a subsite ?

It exists 2 different ways to create subsites in a site collection with REST API. You need to submit an HTTP POST request to one of the following endpoints :

https://<tenant>.sharepoint.com/_api/Web/Webs/Add

http://<tenant>.sharepoint.com/_api/Web/WebInfos/Add

Each endpoint has its own format to submit information to SharePoint to create the site.

In our following example, we will use the first endpoint. If you want more information for the second, please refer to https://msdn.microsoft.com/EN-US/library/office/jj164022.aspx#bk_CreateSite.

To be able to create a site, SharePoint needs some information such as the title, the description, the template and the URL. These information have to be submitted in the body of the HTTP POST request in the following format.

 {
    "parameters":
    {
        "Title":"Sample Team Site",
        "Description":"The description of our new team site",
        "WebTemplate":"STS#0",
        "Url":"SampleTeamSite"
    }
}

As you can see, you have to indicate the name of an available web template. I’m pretty sure that you’re asking yourself, what are the possible values ?

Retrieve the list of available templates

The Office 365 REST API has all the necessary things to retrieve the list of templates available in your Office 365 tenant.

To retrieve the list of these templates, you just have to submit an HTTP GET request to the following endpoint. You need to specify in which language (1033 = English, 1036 = French…) you want to retrieve the templates (with localized titles, descriptions…).

https://<tenant>.sharepoint.com/_api/Web/GetAvailableWebTemplates(lcid=1033)

When you will execute the request above and check the response, you will see a lot of templates. All of them should not be used because they are deprecated, are system templates, etc…

It’s possible to filter the list to only retrieve usable templates by specifying additional parameters in the querystring as you can see below and by using the OData syntax supported by endpoints of the Office 365 REST API.

https://<tenant>.sharepoint.com/_api/Web/GetAvailableWebTemplates(lcid=1033)?$filter=(IsHidden%20eq%20false)%20and%20(IsRootWebOnly%20eq%20false)

In this new request we specify that we don’t want to retrieve hidden templates (IsHidden = false) and templates available for the root site of a site collection (IsRootWebOnly = false).

When you execute the request, you will retrieve a list of desired templates with the following format for each of them.

{
    Description = "A place to work together with a group of people.",
    DisplayCategory = Collaboration,
    Id = 1,
    ImageUrl = "/_layouts/15/images/stts.png?rev=38",
    IsHidden = 0,
    IsRootWebOnly = 0,
    IsSubWebOnly = 0,
    Lcid = 1033,
    Name = "STS#0",
    Title = "Team Site"
}

To create a new site based on a specific template, you just have to get its name in the JSON response (e.g. STS#0 in the sample above).

Retrieve and use a digest token

You’re now able to submit a request with a well-formated HTTP body to create a new subsite but it’s not enough to work.

When you want to execute requests which perform create, update or delete operations, you have to retrieve a digest token and pass it to the HTTP headers of your request.

To retrieve a digest token, you have to submit an HTTP POST request to the following URL.

https://<tenant>.sharepoint.com/_api/ContextInfo

The response for this request is something like what you can see below.

{
    FormDigestTimeoutSeconds = 1800;
    FormDigestValue = "0x1234567890ABCDEF1234567890ABCDEF,14 Mar 2015 20:00:00 -0000";
    LibraryVersion = "16.0.3722.1239";
    SiteFullUrl = "https://<tenant>.sharepoint.com";
    SupportedSchemaVersions =     (
        "14.0.0.0",
        "15.0.0.0"
    );
    WebFullUrl = "https://<tenant>.sharepoint.com";
}

In this response, you have to extract the FormDigestValue, and pass it to your request in a HTTP header named X-RequestDigest.

By default, a digest is valid for 30 minutes (1800 seconds) but you can extract the FormDigestTimeoutSeconds value and add it to the current time to calculate the expiration date (better solution if Microsoft change the default duration in the future).

You’re now able to create a new subsite in a site collection by retrieving the list of available templates, by generating a digest token, and by submitting your creation request to SharePoint with the Office 365 REST API.