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).

var fileInput = $('#fileSelectorInput')[0];

var reader = new FileReader();

reader.onload = function (result) {

var fileData = '';

var byteArray = new Uint8Array(result.target.result)

for (var i = 0; i < byteArray.byteLength; i++) {

fileData += String.fromCharCode(byteArray[i])

}

};

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:

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:

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:

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:

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.

Excellent post and something I have been wondering if this could be done in JS – even if using the WebServices API… I'll have to try and see if I can also get it done with WebServices. Once i get the file into base64 string, I should be able to do it.

I have created "similar" solutions for SP2007 and SP2010 which basically use the upload page inside a manipulated iframe… The user never leaves the page while the page is uploaded.

If somebody get's this working via NAPA and the Current Site's document Library root folder PLEASE SHARE the full source and code. Ideally, I'd like to have a function that can set meta data columns and do some validation (restrict file type, rename the file, check if a combination (name and metadata ) is already there before it uploads. This would be extremely valuable as we have many interfaces where end users are only upload a file with some Identification data.

Interested in this too.. I made an attempt to get this code working on NAPA under a ClientWebPart.aspx page. Had to add a reference jQuery 1.8.2 and tweak some of the code (expected === and new in some places). the form comes up and it locates files. But I get "Oooooops… it looks like something went wrong uploading your file." from IE 10 and Chromebook. I confirmed it's getting a good targetsiteurl, but #__REQUESTDIGEST does not resolve to anything…not sure what this is.

This line is a problem … check *** how can a large file of say 2-3MB be handled or even bigger, what about multiple large files.. would browser be able to handle all that ?

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.

One thing I have found is Digest Value is managed by RequestExecutor so it has not to be set as said in msdn.microsoft.com/…/jj164022(v=office.15).aspx. In fact, if your code is run as a app part it fails, because $("#__REQUESTDIGEST") is undefined.

Here it is working with Office 365 uploading an attachment to a list item using cross domain. It's virtually the same as this blog's solution except for the REST URI. Of course, substitute your own list name for what I have in here (DOH%20News%20Drafts).

For IE8, it does not support the FileReader API, so I'm not sure how you'd use this. I used the built-in attachfile.aspx. Here is some code that works in a napa app. It's up to you to supply this function with the GUID of the list you are attaching to and the itemID of the list item you are attaching to. "readAllAttachments()" is what happens after the file has been uploaded.

Separately, I have code that checks for support of the FileReader API, so you know when to do this. It's simply

if(window.FileReader){use the method from this blog post}else{use this method from this comment}

I am trying to upload large files greater than 10MB(Ex: 40 MB) through SharePoint cross domain Rest API calls. I am able to upload files that are upto 10MB using the code below. But when it comes to files that are greater than 10 MB i am getting an error saying Out of memory. Could someone please help me with uploading large files through SharePoint Rest API. Thanks in advance