Select Page

Recently I was building a prototype SharePoint hosted app to add items into the Host web. The basic operation of the app is that it queries the Host web for specific list types, then allows a user to add a collection of new items to the selected list. So read and write operations.

When dealing with the Host web it is important to remember that you are then subject to ‘cross domain’ calls and the restrictions in place for them. The browser protects users from cross site scripting and specifies that the client code can only access information within the same URL domain.

Thankfully SharePoint comes with some inbuilt options for these calls. The Cross Domain library is the primary option in either JSOM or REST forms.

I’ve been leaning towards REST mainly at the moment primarily as a focus for learning so I could get used to this method of data interactions.

So the first code sample is to get the host web task lists:

NB: This is a cut down extract of the function just to highlight the core request.

var executor;

// Initialize the RequestExecutor with the app web URL.
executor = new SP.RequestExecutor(appWebUrl);

//Get all the available task lists from the host web
executor.executeAsync(
{
url:
appWebUrl +
“/_api/SP.AppContextSite(@target)/web/lists/?$filter=BaseTemplate eq 171&$select=ID,Title,ImageUrl,ItemCount,ListItemEntityTypeFullName&@target='” + hostWebUrl + “‘”,

method: “GET”,

headers: {  “Accept”: “application/json; odata=verbose” },
success: successHandler,
error: errorHandler
}
);

Note from this sample how the host and app web urls are used within the url combined with the SP.AppContextSite. This is the key to invoking a cross domain call in REST using the SP.RequestExecutor

The second snippet of code is the one which adds the new item to the host web list:

NB: This is a cut down extract of the function just to highlight the core request.

var executor;

// Initialize the RequestExecutor with the app web URL.

executor = new SP.RequestExecutor(appWebUrl);

var url = appWebUrl +
“/_api/SP.AppContextSite(@target)/web/lists(guid'” + hostWebTaskList.Id + “‘)/items?@target='” + hostWebUrl + “‘”;

//Metadata to update.
var item = {
“__metadata”: { “type”: hostWebTaskList.ListItemEntityTypeFullName },
“Title”: item.title,
“Priority”: item.priority,
“Status”: item.status,
“Body”: item.body,
“PercentComplete”: item.percentComplete
};

var requestBody = JSON.stringify(item);

var requestHeaders = {
“accept”: “application/json;odata=verbose”,
“X-RequestDigest”: jQuery(“#__REQUESTDIGEST”).val(),
“X-HTTP-Method”: “POST”,
“content-length”: requestBody.length,
“content-type”: “application/json;odata=verbose”,
“If-Match”: “*”
}

executor.executeAsync({
url: url,
method: “POST”,
contentType: “application/json;odata=verbose”,
headers: requestHeaders,
body: requestBody,
success: addPrimeTasksToHostTaskListSuccessHandler,
error: addPrimeTasksToHostTaskListErrorHandler
});

Ok so at this point you’re probably wondering what is the gotcha mentioned in the title. Well here it comes and it’s one of those cut and paste horror stories which costs developers all over the land huge amounts of wasted effort.

So if you take a look at the following block of code

var url = appWebUrl +
“/_api/SP.AppContextSite(@target)/web/lists(guid'” + hostWebTaskList.Id + “‘)/items?@target='” + hostWebUrl + “‘”;

 

//TODO: find out why this works but the below fails with not actually performing the update
//$.ajax({
executor.executeAsync({
url: url,
type: “POST”,
contentType: “application/json;odata=verbose”,
headers: requestHeaders,
data: requestBody,
success: addPrimeTasksToHostTaskListSuccessHandler,
error: addPrimeTasksToHostTaskListErrorHandler
});

You’ll notice i copied over the structure of the method from a normal $.ajax call. THIS IS MY MISTAKE!!!!

As with many things the devil is in the details. By using this ajax snippet I’d introduced a bug which took nearly 4 hours to work out (very little found on the popular search engines about this). The worst part is that the call fires and comes back with a 200 success and even enters the success handler, BUT the action is not performed.

So what is the cause? Well basically there are subtle differences in signature.

  • The ajax call ‘type’ should be ‘method’ in the SP.RequestExecutor
  • The ajax call ‘data’ should be ‘body’ in the SP.RequestExecutor

So there you have it, two word typo’s which throw no errors but cause a logical failure in the code.

I hope this helps someone else avoid the pain Open-mouthed smile

Some really useful information about this capability can be read at:

Chris’ app series covers using this library in anger – http://www.sharepointnutsandbolts.com/2012/11/access-end-user-data-in-host-web-from.html

Apps for Office and SharePoint blog article discussing the inner workings and options for cross domain versus cross site collection – http://blogs.msdn.com/b/officeapps/archive/2012/11/29/solving-cross-domain-problems-in-apps-for-sharepoint.aspx

Using REST in SharePoint apps – http://msdn.microsoft.com/en-us/library/office/jj164022.aspx

One final comment, MSDN Code has this sample: http://code.msdn.microsoft.com/SharePoint-2013-Get-items-7c27024f/sourcecode?fileId=101390&pathId=1361160678 which doesn’t really demo cross domain at the time of writing as it isn’t using the code correctly against the host web in my opinion.