Friday, November 29, 2013

More SharePoint 2013 REST Code Tips

Technorati Tags: ,,,

I continue to use the SharePoint 2013 REST api when ever I can. It simplifies my java script code and does not require that I include all the JSOM dependent java script files. It is truly amazing what you can accomplish with this REST api. Unfortunately, it’s secrets are difficult to decipher. So once again I am going to list some example code to hopefully help you be more productive with the REST api. These code examples do various things but may give you insight into what the REST api is capable of.

Logging Analytics Usage Events

There are many undiscovered REST method calls in SP2013 and one I thought might be useful is the ability to log analytic usage events from your SharePoint app. Using this you can add usage metrics about your app to the standard analytics reporting.

function logUsageEvent() {

var restSource = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"))
+ "/_api/Microsoft.SharePoint.Administration.SPAnalyticsUsageService/logevent"

$.ajax(
{
url: restSource,
method: "POST",
data:JSON.stringify( {
usageEntry: {
"__metadata": { "type": "Microsoft.SharePoint.Administration.UsageEntry" },
"EventTypeId": 1,
"ItemId": "anything you want",
"Site": "a975b994-fc67-4203-a519-b160175ca967",
"User": "johndoe"
}
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function (data) {
var d = data;
},
error: function (err) {
alert(JSON.stringify(err));
},
}
);

}


This example uses the fully qualified type name for the SPAnalyticsUsageService in the url. This will work. You should use an alias whenever possible. In this case the alias for this type is “events”. As you use this api more you will learn that not all types have an alias. Aliases are also difficult to discover in the api. Please note the type parameter of “Microsoft.SharePoint.Administration.UsageEntry”. This is the OData model type used in this call. You would never figure this out unless it was documented. This is because this type is marked as internal and is undiscoverable unless your using a tool like reflector. Secondly, you must set the parameter name of “usageEntry”. Once again this fact is not evident unless your reflecting the server stub class for Microsoft.SharePoint.ServerStub. The EventTypeId can be any of the following:

First 1
Last 3
None 0
RecommendationClick 3
RecommendationView 2
View 1


You can just use 0 for custom events and supply whatever text you want in the itemId parameter. The site, scopeId and user parameters are optional. If these are not sent then the server code uses the current site and user.



Getting User Permissions for a Document Library



Using the REST api to get user permissions I found takes two steps. One you must get the user’s account name and then send this to get the permissions for the document library. You can also do this for web resources.



function getUserName() {
var uri = new URI(document.URL)
var appVar = uri.getQueryParameter("SPAppWebUrl");

var restSource = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"))
+ "/_api/SP.UserProfiles.PeopleManager/GetMyProperties"

$.ajax(
{
url: restSource,
method: "GET",
headers: {
"accept": "application/json; odata=verbose",
},
success: function (data) {
var userAccountName = data.d.AccountName;
getUserPermissionsREST(userAccountName);

},
error: function (err) {
alert(JSON.stringify(err));
},
}
);
}

}

function getUserPermissions(accountName) {
hostweburl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));

userUrl = appweburl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('Documents')/getusereffectivepermissions('" + accountName + "')?@target='" + hostweburl + "'";

$.ajax({
headers: { "Accept": "application/json;odata=verbose" },
contentType: 'application/json',
url: userUrl,
success: function (data) {
var mydata = data;
},
error: function (err) {
alert(JSON.stringify(err));
}
});
}


Adding a Site Group to a Web



Add a new group to a web was perplexing. The issue is what exactly is the complex type name that needs to be sent. Many times when calling the REST api you will receive the “type does not exist in the model” error. Discovering which type name was trial an error. The server stub points to the Microsoft.SharePoint.SPGroupEntityData but this was wrong. So the code below works using “SP.Group”. Also, there is always logic you need to contend with on the server side. So even if you send the correct parameters you will have to make sure the OwnerTitle and LoginName are the same otherwise you will receive the cryptic standard parameter value not recognized error. Finally, you will notice that url contains the alias “sitegroups”. Once again this alias is not discoverable from the server stub but only through reflecting the attributes of the SPGroup class. Never the less this is only a convenience alias and you can just use “Microsoft.SharePoint.SPGroupCollection” in the url. You will notice also there is no method call but just a posting of a data payload. This is because the SharePoint collections expose an intrinsic method on the server side to use. So just posting a payload with the correct parameters will add the json object to the collection.



function addSiteGroup() {
appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
hostweburl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
var urlTemplate = appweburl + "/_api/SP.AppContextSite(@target)/web/sitegroups?@target='" + hostweburl + "'";

$.ajax({
url: urlTemplate,
type: "POST",
data: JSON.stringify({
'__metadata': { 'type': 'SP.Group' },
'Description': 'Rest Group',
'OwnerTitle': 'domain\steve.curran',
'LoginName':domain\steve.curran'
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"content-length": 80,
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function (data) {
var d = JSON.parse(data.body);

},
error: function (err) {
alert(JSON.stringify(err));
}
});

}


The Discovery Continues


I will continue to post more examples in future posts including things that just cannot be done using REST even though the api supports it. An example of this is adding a field to a contenttype. The REST api  exposes the contenttype collection and has an intrinsic method for adding a field but the server object model will not add it since the collection is listed as read only. The read only check is only applied in the REST method but is not applied in the JSOM method.

The REST api is a mystery. My next post will illustrate how the api works with the “server stub” assemblies. These assemblies are the key to writing valid and working REST calls. I am also working on a SharePoint 2013 Remote API Discovery Visual Studio extension, hopefully, this would help us all become more productive and effective SharePoint app developers.