Manipulating list items in SharePoint Hosted Apps using the REST API

In this post I will describe how to use the REST API to manipulate list items from within a SharePoint hosted App. For information on the different hosting options available (Azure Auto hosted and Provider Hosted Apps) there is a good MSDN article here.

Introduction

The REST API in SharePoint 2013 provides developers with a simple standardised method of accessing information contained within SharePoint. It can be used from any technology that is capable of sending standard http requests and is particularly useful for developers who are not familiar with the Client Side Object Model. For a full list of advantages and disadvantages of the REST API, and for a comparison with other API’s click here.

This article does not cover App Permissions. For information about permissions there is a good MSDN article here. Use of the REST API in other hosting options, whilst similar to SharePoint Hosted Apps, is not covered in this article.

Obtaining the site URI

One key prerequisite to interacting with SharePoint lists items is to obtain the correct URI for the SharePoint site the list is hosted in. There are multiple ways to do this:

  1. On SharePoint pages _spPageContextInfo.siteAbsoluteUrl contains the URI to the site that the app is installed within (the parent site).
  2. You can include a set of standard tokens in the URL attribute of both pages and web parts. Adding {StandardTokens} will include the following 7 parameters to the url; SPHostUrl, SPHostTitle, SPAppWebUrl, SPLanguage, SPClientTag, SPProductNumber, and SenderId. These will need to be split out of the URL to be used. There are multiple ways to do this. The simplest is to loop through all the parameters until you find the parameter you are looking for. The following snippet of code searches for the SPAppWebUrl.

 

  1. var params = document.URL.split("?")[1].split("&");
  2. for (var i = 0; i < params.length; i = i + 1) {
  3.     var param = params[i].split("=");
  4.     switch (param[0]) {
  5.         case"ParameterName":
  6.             Variable = decodeURIComponent(param[1]);
  7.             break;        
  8.             // add additional cases for other parameters here, for example:
  9.             // case "OtherParameterName":
  10.             // DifferentVariable = parseInt(decodeURIComponent(param[1]));
  11.             // break;    
  12.     }
  13. }

There are several different tokens that you can include in the url's used to open pages within your App. For more information about the different tokens and some basic information about each of them click here. To add the tokens to your start page you can use the visual designer for the App's manifest file. The setting can be found on the ‘General’. It is worth noting that the manifest editor has changed significantly since the original release of the developer tools. If you are using an old version of the tools then this setting may be in a different place.

You can also add the tokens using the source code editor. The following example shows the start page url where the standard tokens have been added (note that ?{StandardTokens} has been appended to the StartPage url):

  1. <Properties>
  2.   <Title>Example CRUD Operations</Title>
  3.   <StartPage>~appWebUrl/Pages/Default.aspx?{StandardTokens}</StartPage>
  4. </Properties>

 

REST URI Operators

Once you have the correct base URI the next step is to determine the correct URI for the list with which you would like to interact. The REST endpoint exposes the same GetByTitle() method that the Client Side Object Model offers and can be used by appending “/_api/web/lists/getbytitle(title)” to the end of the base URI. More information about the REST endpoint can be found in this MSDN article.

 

List Item Types

To update or create list items you will need to include the list item type. This is a string automatically created by SharePoint when the list is first created. Two possible ways to obtain this are:

  1. Perform a read operation on the list and locate the type within the returned set of elements. In JSON format the type can be found within the __metadata attribute of all of the returned list items. In Atom/xml format (the default format returned if you query from a web browser) you can find it in the category scheme attribute (labelled ‘term’) within the item.
  2. You can attempt to generate the value from the list name. In general list item types follow the convention SP.Data.ListNameListItem (e.g. list name is “Test”, list item type is SP.Data.TestListItem). However this is not always the case. For example SharePoint automatically capitalises the first letter of the list name (e.g. list name “test” list item type is SP.Data.TestListItem). The following code snippet shows how to generate the List Item Type based on the list name.

 

  1. function GetItemTypeForListName(name) {
  2.     return"SP.Data." + name.charAt(0).toUpperCase() + name.slice(1) + "ListItem";
  3. }

 

Request Digests

A replay attack occurs when a valid request is sent to the server and a copy of that request is stored. The request is then sent multiple times (replayed). This can result in a variety of different issues the most common of which is duplication of data. To prevent this, SharePoint requires the user to include a request digest value with each create, update and delete operation. This value is then used by SharePoint to identify non-genuine requests. Inside SharePoint Hosted apps, the request digest can be found by reading the value of the “__REQUESTDIGEST” object within the html page.

  1. var digestValue = $("#__REQUESTDIGEST").val()

Note: this will only work on pages that contain the SharePoint Chrome element. The example above requires JQuery to work.

eTags

When updating or deleting items within SharePoint lists via REST you must specify the Entity Tag (eTag) value that was returned with the item during the initial query. This enables SharePoint to determine if the item has changed since it was requested. Alternatively you can tell SharePoint to perform the operation regardless by specifying * as the eTag value. For example:

  1. “If-Match”: item.__metadata.etag can be used to specify the actual eTag value (‘item’ is the object returned from SharePoint containing the list item in JSON format).
  2. “If-Match”: “*” can be used to match any eTag value resulting in the operation being performed regardless of the actual value.

The examples above can be found in the code sample at the end of this article. They form part of the Ajax call for updating an item. eTags are part of the HTTP Protocol V1.1, more information on the topic can be found here.

Cross Domain Calls

Cross domain calls are blocked by modern web browsers due to security concerns. This is a common issue in web based development and is particularly relevant due to the nature of SharePoint hosted Apps. For example, when accessing data in the parent web (https://Sharepoint.com) from an App (hosted at https://Apps.SharePoint.com/MyApp) the calls will be blocked. To get round this you can use the SP.RequestExecutor.js script to relay messages to SharePoint from within the same domain.

To do this you will need to load the JavaScript file from the host web and then use it to execute the REST queries across the network. The following example shows how to do this.

  1. var SPHostUrl;
  2. var SPAppWebUrl;
  3. var ready = false;
  4.  
  5. // this function is executed when the page has finished loading. It performs two tasks:
  6. // 1. It extracts the parameters from the url
  7. // 2. It loads the request executor script from the host web
  8. $(document).ready(function () {
  9.     var params = document.URL.split("?")[1].split("&");
  10.     for (var i = 0; i < params.length; i = i + 1) {
  11.         var param = params[i].split("=");
  12.         switch (param[0]) {
  13.             case"SPAppWebUrl":
  14.                 SPAppWebUrl = decodeURIComponent(param[1]);
  15.                 break;
  16.             case"SPHostUrl":
  17.                 SPHostUrl = decodeURIComponent(param[1]);
  18.                 break;
  19.         }
  20.     }
  21.  
  22.     // load the executor script, once completed set the ready variable to true so that
  23.     // we can easily identify if the script has been loaded
  24.     $.getScript(SPHostUrl + "/_Layouts/15/SP.RequestExecutor.js", function (data) {
  25.         ready = true;
  26.     });
  27. });
  28.  
  29. // this function retrieves the items within a list which is contained within the parent web
  30. function GetItems() {
  31.  
  32.     // only execute this function if the script has been loaded
  33.     if (ready) {
  34.  
  35.         // the name of the list to interact with
  36.         var listName = "MyList";
  37.  
  38.         // the url to use for the REST call.
  39.         var url = SPAppWebUrl + "/_api/SP.AppContextSite(@target)" +
  40.  
  41.             // this is the location of the item in the parent web. This is the line
  42.             // you would need to change to add filters, query the site etc
  43.             "/web/lists/getbytitle('" + listName + "')/items?" +
  44.             "@target='" + SPHostUrl + "'";
  45.  
  46.         // create new executor passing it the url created previously
  47.         var executor = new SP.RequestExecutor(SPAppWebUrl);
  48.  
  49.         // execute the request, this is similar although not the same as a standard AJAX request
  50.         executor.executeAsync(
  51.             {
  52.                 url: url,
  53.                 method: "GET",
  54.                 headers: { "Accept": "application/json; odata=verbose" },
  55.                 success: function (data) {
  56.  
  57.                     // parse the results into an object that you can use within javascript
  58.                     var results = eval(JSON.parse(data.body));
  59.                 },
  60.                 error: function (data) {
  61.  
  62.                     // an error occured, the details can be found in the data object.
  63.                     alert("Ooops an error occured");
  64.                 }
  65.             });
  66.     }
  67. }

 

Note: the middle line of the URL variable is where you would change the address that the REST call is sent to. For example to get information about a list rather than its items you can remove “/items” leaving "/web/lists/getbytitle('" + listName + "')?"

 

Example Operations

This section contains sample code for all of the CRUD operations. All of this sample code can be found in the source code which is available for download. The request executor is not needed in this example since the site URL is in the same domain as the app.

Create

The following snippet of code shows how to perform a Create operation against a SharePoint list. The first line of the function is a call to a method which returns a list item type based on the name of the list using the rules mentioned previously. The next 4 lines create a JavaScript object which contains the information about the item that should be created including values for each of the fields and the item type. The reminder of the function executes the ajax call and then calls either the success or failure functions (passed into the function as parameters).

  1. // CREATE Operation
  2. // listName: The name of the list you want to get items from
  3. // siteurl: The url of the site that the list is in. // title: The value of the title field for the new item
  4. // success: The function to execute if the call is sucesfull
  5. // failure: The function to execute if the call fails
  6. function createListItemWithDetails(listName, siteUrl, title, success, failure) {
  7.  
  8.     var itemType = GetItemTypeForListName(listName);
  9.     var item = {
  10.         "__metadata": { "type": itemType },
  11.         "Title": title
  12.     };
  13.  
  14.     $.ajax({
  15.         url: siteUrl + "/_api/web/lists/getbytitle('" + listName + "')/items",
  16.         type: "POST",
  17.         contentType: "application/json;odata=verbose",
  18.         data: JSON.stringify(item),
  19.         headers: {
  20.             "Accept": "application/json;odata=verbose",
  21.             "X-RequestDigest": $("#__REQUESTDIGEST").val()
  22.         },
  23.         success: function (data) {
  24.             success(data);
  25.         },
  26.         error: function (data) {
  27.             failure(data);
  28.         }
  29.     });
  30. }

 

Read

Reading items is probably the simplest of all of the CRUD operations. The code below shows the simplest form of a read operation. A simple ajax call is executed against the SharePoint server. If the call succeeds then the success function (passed in as a parameter) is called, if it fails then the failure function (also passed in as a parameter) is called. In both cases the data returned from the server is passed through to the function. The code sample also includes an example of how to retrieve an item based on its ID.

  1. // READ opperation
  2. // listName: The name of the list you want to get items from
  3. // siteurl: The url of the site that the list is in.
  4. // success: The function to execute if the call is sucesfull
  5. // failure: The function to execute if the call fails
  6. function getListItems(listName, siteurl, success, failure) {
  7.     $.ajax({
  8.         url: siteurl + "/_api/web/lists/getbytitle('" + listName + "')/items",
  9.         method: "GET",
  10.         headers: { "Accept": "application/json; odata=verbose" },
  11.         success: function (data) {
  12.             success(data);
  13.         },
  14.         error: function (data) {
  15.             failure(data);
  16.         }
  17.     });
  18. }

 

Update

In contrast to reading list items updating them is probably the hardest operation. To update an item you will need to obtain the URL of the item and, depending on your handling of eTags, the eTag value. The simplest way to do this is to perform a get operation and then use the properties of the item. The update method uses the same method mentioned for update operations to generate the list item type.

The first line of this function calls a method to get the list item type for the specified list. The next four lines create a JavaScript object containing details of the list item. The next line is a call to a get operation (similar to the one described previously) which returns the list item to be updated. This allows us to extract the eTag and item url and makes it easier to update. If this is successful then the call to update the item is executed and either the success or failure function is executed depending on the result.

  1. // Update Operation
  2. // listName: The name of the list you want to get items from
  3. // siteurl: The url of the site that the list is in. // title: The value of the title field for the new item
  4. // itemId: the id of the item to update
  5. // success: The function to execute if the call is sucesfull
  6. // failure: The function to execute if the call fails
  7. function updateListItem(itemId, listName, siteUrl, title, success, failure) {
  8.     var itemType = GetItemTypeForListName(listName);
  9.  
  10.     var item = {
  11.         "__metadata": { "type": itemType },
  12.         "Title": title
  13.     };
  14.  
  15.     getListItemWithId(itemId, listName, siteUrl, function (data) {
  16.         $.ajax({
  17.             url: data.__metadata.uri,
  18.             type: "POST",
  19.             contentType: "application/json;odata=verbose",
  20.             data: JSON.stringify(item),
  21.             headers: {
  22.                 "Accept": "application/json;odata=verbose",
  23.                 "X-RequestDigest": $("#__REQUESTDIGEST").val(),
  24.                 "X-HTTP-Method": "MERGE",
  25.                 "If-Match": data.__metadata.etag
  26.             },
  27.             success: function (data) {
  28.                 success(data);
  29.             },
  30.             error: function (data) {
  31.                 failure(data);
  32.             }
  33.         });
  34.     }, function(data){
  35.         failure(data);
  36.     });
  37. }

 

Delete

The code below performs a delete operation. In a similar way to updating items delete operations are performed using the URI of the item and depending on how eTags are handled the eTag value of the item. In this example the item is first retrieved and then its properties (uri and eTag) are used to execute the delete operation.

  1. // Delete Operation
  2. // itemId: the id of the item to delete
  3. // listName: The name of the list you want to delete the item from
  4. // siteurl: The url of the site that the list is in.
  5. // success: The function to execute if the call is sucesfull
  6. // failure: The function to execute if the call fails
  7. function deleteListItem(itemId, listName, siteUrl, success, failure) {
  8.     getListItemWithId(itemId, listName, siteUrl,function (data) {
  9.         $.ajax({
  10.             url: data.__metadata.uri,
  11.             type: "POST",
  12.             headers: {
  13.                 "Accept": "application/json;odata=verbose",
  14.                 "X-Http-Method": "DELETE",
  15.                 "X-RequestDigest": $("#__REQUESTDIGEST").val(),
  16.                 "If-Match": data.__metadata.etag
  17.             },
  18.             success: function (data) {
  19.                 success(data);
  20.             },
  21.             error: function (data) {
  22.                 failure(data);
  23.             }
  24.         });
  25.     },
  26.    function (data) {
  27.        failure(data);
  28.    });
  29. }

 

Source Code

The following downloadable source code contains a working example of all four operations. To run the example you will need to configure the SiteUrl of the project to point to a SharePoint 2013 developer site. To do this click on the project in solution explorer and open up the properties task pane. Enter the URL of your site into the SiteUrl box and then press F5.

The sample contains a page hosted within the App Web which interacts with a list in the Parent Web. When you install the App you will be asked to select a list and trust it. The list you select must contain a Title column (a new custom list will work just fine). To use the App enter the name of the list you want to access data from (this must match the list you selected when you trusted the App) and then use the controls under each of the four headings. The code is all contained within the App.js file of the project.

Please Note: to run this sample you will also need access to a SharePoint server which has been configured for Apps. The simplest way to do this is to create an Office 365 developer account. Alternatively you can install SharePoint on your own server. There is a guide to configuring SharePoint 2013 servers for Apps here.

Example CRUD Operations.zip