Testing

webTiger Logo Wide

Accessing Lists on the Host Web From a SharePoint Add-in

SharePoint 2013 Logo

When developing SharePoint Add-ins there may be times when you want to access and store some data on the host web an app instance has been deployed to instead of holding it on the app web (as the app instance website is the default).

If that is the case then you may become frustrated that you can’t access the host web’s lists due to permissions issues, especially if you have properly set up your SharePoint fully-qualified domain name (FQDN) to be isolated from the Add-ins FQDN, as recommended by Microsoft.

The good news is Microsoft provided a simple way of getting around these permissions issues in all their recent programming APIs. This article explains how to achieve this using both JSOM and REST approaches.

The approach taken by both SharePoint’s JSOM and RESTful APIs is to use an encapsulated client context that implicitly manages authentication behind the scenes. The query string data in the URL used to access an instance of a SharePoint Add-in should hold the full URL of both the app web and host web sites.

To access the app web URL just retrieve the ‘SPAppWebUrl’ query string value.

To access the host web URL just retrieve the ‘SPHostUrl’ query string value.

Using JSOM to Access Host Web Resources

In a normal JSOM query we’d initialise a client context, queue up some queries, execute them, and then use the data retrieved. Something similar to the code below:

var context = SP.ClientContext.get_current();
var list = context.get_web().get_lists().getByTitle('MyList');
var items = list.get_items();
context.load(list);
context.load(items);
context.executeQueryAsync(
    function (sender, args) { // success
        var iterator = items.getEnumerator();
        while (iterator.moveNext()) {
            // Do something with each list item!
        }
    },
    function (sender, args) { // failure
        console.error('SP-ERROR: ' + args.get_message());
    }
);Code language: JavaScript (javascript)

If we are trying to access the host web instead of the current context the web session is in, then we have to do a little more work.

First we need to get the host web’s URL – and we’re using JavaScript’s URLSearchParams class for this for simplicity. It is worth mentioning that this class may not be supported by all web browsers (although the most popular modern browsers should all support it).

Next, we need to create an encapsulated context that will allow us to access the host web without permissions issues and we can use JSOM’s SP.AppContextSite class for this. The class requires the current app web client context and the host web URL as inputs.

Once we’ve got a working context to the host web, we can use it to perform queries. The above code would be rewritten to access ‘MyList’ on the host web like so:

// Get the query string parameter value for the host web.
var qsParameters = new URLSearchParams(window.location.search);
var hostUrl = qsParameters.get('SPHostUrl');

// Get the current (app web) client context, and use that to create a context for the host web.
var context = SP.ClientContext.get_current();
var hostContext = new SP.AppContextSite(context, hostUrl);

// Now queue up and execute the queries as normal, but using the host context instead of the app web one.
var list = hostContext.get_web().get_lists().getByTitle('MyList');
var items = list.get_items();
context.load(list);
context.load(items);
context.executeQueryAsync(
    function (sender, args) { // success
        var iterator = items.getEnumerator();
        while (iterator.moveNext()) {
            // Do something with each list item!
        }
    },
    function (sender, args) { // failure
        console.error('SP-ERROR: ' + args.get_message());
    }
);Code language: JavaScript (javascript)

A fairly small, and relatively simple, change once we know what we are doing!

Accessing Host Web Resources Using the REST API

The same technique as used above for JSOM is used when accessing the host web from an add-in with SharePoint’s REST API. It looks a little different but it is really just doing the same thing. Consider the following query in REST:

var queryUrl = 'https://site-url/_api/web/lists/getbyTitle(\'MyList\')/Items?$select=Title,Created';
// (Execution of queryUrl request omitted for brevity.)Code language: JavaScript (javascript)

The above request will query the specified site (if we replace ‘site-url’ with a valid SharePoint site address) and return all items from the MyList list.

If we wanted to perform the same query but from an app web that is requesting data from it’s host web, then we could modify the above request like this:

var qsParameters = new URLSearchParams(window.location.search);
var hostUrl = qsParameters.get('SPHostUrl');
var queryUrl = 'https://app-web-url/_api/SP.AppContextSite(@hostWeb)/web/lists/getbyTitle(\'MyList\')/Items?$select=Title,Created&@hostWeb=\'' + hostWebUrl + '\'';
// (Execution of queryUrl request omitted for brevity.)Code language: JavaScript (javascript)

In case it isn’t immediately obvious how the URL has changed, it was only two additions that we’ve needed to make:

  • Insert SP.AppContextSite(@hostWeb) in the middle of the API call.
  • Add a query string parameter for our new @hostWeb variable that specifies the full URL of the host web site.

That’s all there is to it!