Uploading Files Using the REST API and Client Side Techniques

Over the past few months I have, on several occasions, been asked how to upload a file to SharePoint using nothing more than JavaScript, HTML and the REST API. A few weeks ago, on a customer project, I was asked to do exactly that and was astonished to find that there is sparse documentation and even fewer examples out there on the Internet. For this reason, I have decided to write a post on how to use HTML 5 and JavaScript to upload files to a SharePoint 2013 document library.

Please Note: This technique is only supported in browsers that support the FileReader object of the File API. Currently this includes, but is not limited to, Internet Explorer version 10, Firefox version 3.6 and Chrome version 7 (information about the File API, including the FileReader object can be found here).

There are two specific areas that I will cover in this article; how to extract the file from the user’s machine and how to post this file off to the correct document library (including how to upload into a folder).Please note that this article does not cover the authentication aspect of uploading files over REST. If you are performing the upload from a SharePoint hosted app then this is taken care of by the app model. If you are performing an upload from another source then you will need to include an OAuth token (either as an App or as a user) with the request by setting an additional header (“authorization”).

Getting the file

Traditionally, uploading files is achieved by using a form that POSTs off to a web server which then handles the upload. This means that developers do not have to directly reach into the client’s file system to obtain the file. However this also means that you need to have access to a web server where you can handle the upload. In some situations, SharePoint hosted apps for example, the developer does not have access to this infrastructure and the upload must be handled inside the client’s web browser.

Advancements in the JavaScript File API allow developers to access the local file system using a standard input tag. The magical part is that you can access the file contents without having to perform a post back. The JavaScript code below shows how you can read the contents of a file (assuming that you have an input tag of type file inside the HTML document with an ID of fileSelectorInput).

  1. var fileInput = $('#fileSelectorInput')[0];
  2. var reader = new FileReader();
  3. reader.onload = function (result) {
  4.     var fileData = '';
  5.     var byteArray = new Uint8Array(result.target.result)
  6.     for (var i = 0; i < byteArray.byteLength; i++) {
  7.         fileData += String.fromCharCode(byteArray[i])
  8.     }
  9. };
  10. reader.readAsArrayBuffer(fileInput.files[0]);

The example first uses jQuery to obtain a reference to the input tag on the page. A new FileReader object is then created and the readAsArrayBuffer function is called on the FileReader passing in a reference to the first file in the list.

The onload function contains the contents of the file (inside result.target.result) however this is in the format of an ArrayBuffer. To upload the file to SharePoint this must be converted into a string which can then be set as the body of a POST operation. This can be done by iterating through the array and building up a string using the string.fromCharCode() function. Details of this encoding method can be found in this MSDN article.

Performing the upload

Performing the actual upload is relatively simple. In the example code at the end of this article I will be using the cross domain library provided with SharePoint 2013 to perform uploads from within a SharePoint Hosted App. This library allows for cross domain calls from pages in the App web to the parent site. I will also show the endpoints required to upload files without the cross domain library.

Uploading to the root folder of a document library (without the cross domain library)

This is probably the simplest endpoint that I will cover. TargetSite needs to be replaced with the URL of the SharePoint site (e.g. https://sharepoint.com/sites/site). Additionally, the final two parameters (TargetLibrary and TargetFileName) need to be replaced with the appropriate values. The URL is:

TargetSite/_api/web/lists/getByTitle(@TargetLibrary)/RootFolder/Files/add(url=@TargetFileName,overwrite='true')?@TargetLibrary='LibraryName'&@TargetFileName='Target File Name'

Uploading to the root folder of a document library (with the cross domain library)

If you would like to perform the upload from a SharePoint hosted App you will need to use the cross domain library to overcome cross domain issues. This can be done by modifying the start of the URL and adding an additional parameter (TargetSite) which needs to be replaced with the URL of you target site (e.g. https://sharepoint.com/sites/site). You will also need to replace the AppWebUrl section with the URL of your AppWeb. All other parameters should stay the same. The URL is:

AppWebUrl/_api/SP.AppContextSite(@TargetSite)/web/lists/getByTitle(@TargetLibrary)/RootFolder/Files/add(url=@TargetFileName,overwrite='true')?@TargetSite=’Target site URL’&@TargetLibrary=’LibraryName’&@TargetFileName=’Target File Name’ 

Uploading to a folder within a document (without the cross domain library)

Uploading to a folder in a document library is fairly similar to uploading to the root folder. Again I will show two examples (one with and one without the cross domain library). The simplified version (without the cross domain library) can be performed using the URL below. You will need to replace the various components in the same way as you would for uploading to the root folder (mentioned previously). Also note the addition of a TargetFolder parameter and the change to URL to include the folder. The URL is:

TargetSite/_api/web/lists/getByTitle(@TargetLibrary)/RootFolder/folders(@TargetFolderName)/files/add(url=@TargetFileName,overwrite='true')?@TargetLibrary=’LibraryName’&@TargetFolder=’Target Folder Name’&@TargetFileName=’Target File Name

Uploading to a folder within a document (with the cross domain library)

You can also use the cross domain library to upload files to a folder within a document library. The URL needs to be modified slightly (in the same way as before) to redirect the message to the AppWeb and to include the TargetSite parameter. The URL is:

AppWebUrl/_api/SP.AppContextSite(@TargetSite)/web/lists/getByTitle(@TargetLibrary)/RootFolder/folders(@TargetFolderName)/files/add(url=@TargetFileName,overwrite='true')?@TargetSite='Target site url’&@TargetLibrary=’LibraryName’&@TargetFolder=’Target Folder Name’&@TargetFileName=’Target File Name’ 

Required Headers/Options

In addition to ensuring you use the correct endpoint and encoding, it is important to ensure that the correct headers/options are set on the request. The actual request should be sent as a POST operation and the content type, headers, content length and binary string request body options must be set.

Accept: The Accept option must be set equal to “application/json; odata=verbose” inside the headers of the request.
Digest Value: The digest value should be set equal to the digest value obtained from SharePoint. This should also be set in the headers section of the request. The digest value can be read from SharePoint pages or be requested from the app web. More information about digest values can be found here under the heading “Writing data by using the REST interface”.
Content Type: The content type of “application/json; odata=verbose” should be set on the request
Body: The body should be set equal to the file contents encoded as per the description in the MSDN article here.
BinaryStringRequestBody: The option “binaryStringRequestBody” should be set equal to true. This informs SharePoint that the body of the message contains binary data.
Content Length: The content length of the request should be set equal to the length of the body. Note: if you are using the request executor then the content length is optional, if you are uploading directly (without the request executor) then you must set the content length otherwise SharePoint will reject the request.

Conclusion

In summary, performing uploads via the REST API using only client side technologies is not only possible, but is actually quite simple. We have looked at how to extract the file from the user’s machine, generate the correct endpoint and set the correct headers/options on the request. When you put all of this together you can upload binary files to SharePoint from the end users web browser without having to process the files server side. This means that in situations such as SharePoint hosted Apps where developers do not have access to server side code uploads can still be performed. Furthermore in situations where you do have access to server side code you can still use the endpoints mentioned to upload files using the REST API.

The source code below contains a working example (in the form of a SharePoint hosted App).

 

Source Code

The following downloadable source code contains a working example of uploading files over REST. The sample is contained within a SharePoint hosted app and you will need to have Visual Studio 2012 installed to be able to run it. 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.

Upload Over REST Example.zip