SharePoint Rest API Handler
SharePoint contains a lot of Rest API’s that can be used for many scenario’s. You could use them for example in desktop and windows phone applications. When using these API’s you need to make sure authentication is handled before calling the API. For authenticating to these API’s there a couple of options:
- Authenticate as a User. This is a registered user with a license within your Office 365 tenant or your on-premise AD.
- Authenticate as a Application. You can register a application within an SharePoint site by using the “AppRegNew.aspx” page and perform actions on behalf of a application.
The token that is received from the authentication request needs to be supplied in the header of the API call. In order to retrieve the token you can make use of the “TokenHelper” class that is added by default to SharePoint App projects.
With the token the API call can be made, this needs do be done in different ways. In the following paragraphs there are examples for Getting Items, Uploading documents, Updating, Getting documents by Id.
Getting Items from a SharePoint List
Getting items from a SharePoint list can be achieved by using a Http Get to the “GetItems” API method and supplying a Caml query in the URL.
- [siteurl]/_api/web/lists/GetByTitle('[listname]')/GetItems(query=@v1)?@v1={"ViewXml":"[camlquery]"}
Example for a Caml query is displayed below. Make sure you supply a query with the “View” and “Query” tag included.
<View> <ViewFields> <FieldRef Name='LinkFilename' /> </ViewFields> <Query> <OrderBy> <FieldRef Name='Created' /> </OrderBy> </Query> </View>
In C# the API call can be made in the following way:
public string GetItems(string siteUrl, string list, string camlQuery) { string retVal = string.Empty; string data = camlJson.Replace("{0}", camlQuery); camlQuery = "(query=@v1)?@v1={\"ViewXml\":\"{2}\"}".Replace("{2}", camlQuery); string url =string.Format(CultureInfo.InvariantCulture, "{0}/_api/web/lists/GetByTitle('{1}')/GetItems{2}", siteUrl, list, camlQuery); SPAPIHandler handler = new SPAPIHandler(ClientId, ClientSecret); retVal = handler.Post(url); return retVal; }
Getting a Document by Id
Getting a specific item from a SharePoint list can be achieved by using a Http Get to the “Items” API method and supplying with specific select and filter string.
- [siteurl]/_api/web/lists/getByTitle('[listname]')/items?$select=EncodedAbsUrl&$filter=Id eq [Id]
The select query in the above method retrieves the “EncodedAbsUrl” this is the URL to the specific document. Within C# you can use the following method to retrieve the specific document.
public string GetDocument(string siteUrl, string list, string Id) { string retVal = string.Empty; string url = string.Format(CultureInfo.InvariantCulture, "{0}/_api/web/lists/getByTitle('{1}')/items?$select=EncodedAbsUrl&$filter=Id eq {2}", siteUrl, list, Id); SPAPIHandler handler = new SPAPIHandler(ClientId, ClientSecret); retVal = handler.Get(url); return retVal; }
Uploading a Document
Uploading documents to a SharePoint library can be achieved by using a Http Post to the “Add” API method. When uploading a document it is not possible to also add metadata directly. This needs to be done within a separate call.
- [siteurl]/_api/web/lists/getByTitle('[listname]')/RootFolder/Files/Add(url='[filename]', overwrite=true)
The document itself needs to be added to the content of the post message. In C# the complete method looks like this:
public string PostDocument(string siteUrl, string list, Document document) { string retVal = string.Empty; string url = string.Format(CultureInfo.InvariantCulture, "{0}/_api/web/lists/getByTitle('{1}')/RootFolder/Files/Add(url='{2}', overwrite=true)", siteUrl, list, document.FileName); SPAPIHandler handler = new SPAPIHandler(ClientId, ClientSecret); retVal = handler.PostDocument(url, document.DocumentByteArray); JavaScriptSerializer serializer = new JavaScriptSerializer(); dynamic item = serializer.Deserialize<object>(retVal); string relativeUrl = item["d"]["ServerRelativeUrl"]; UpdateDocument(siteUrl, relativeUrl, document); return retVal; }
Updating a Document
As mentioned in the above paragraph updating a document is done in a separate Http method that also needs some additional headers.
- [siteurl]/_api/web/GetFileByServerRelativeUrl('[file relative url]')/ListItemAllFields
The relative URL of the file can be retrieved from the result of the upload request. This can be seen in the paragraph above where the result message is serialized in a dynamic object and the “ServerRelativeUrl” property is retrieved.
The complete C# method for updating a document is:
public string UpdateDocument(string siteUrl, string relativeUrl, Document document) { string retVal = string.Empty; string url = string.Format(CultureInfo.InvariantCulture, "{0}/_api/web/GetFileByServerRelativeUrl('{1}')/ListItemAllFields", siteUrl, relativeUrl); SPAPIHandler handler = new SPAPIHandler(ClientId, ClientSecret); retVal = handler.Merge(url, document); return retVal; }
SharePoint API Handler
As you can see in the examples above they all make use of the “SPAPIHandler” class. This class takes care of the HTTP calls and authenticates the requests.
public class SPAPIHandler { private string contenttype = "application/json;odata=verbose"; private string acceptHeader = "application/json;odata=verbose"; /// <summary> /// Gets or sets the client identifier. /// </summary> /// <value> /// The client identifier. /// </value> private string ClientId { get; set; } /// <summary> /// Gets or sets the client secret. /// </summary> /// <value> /// The client secret. /// </value> private string ClientSecret { get; set; } public SPAPIHandler(string clientId, string clientSecret) { ClientId = clientId; ClientSecret = clientSecret; } public string Get(string url) { var accessToken = GetAccessTokenResponse(url); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.Method = "GET"; request.Accept = acceptHeader; request.Headers.Add("Authorization", accessToken.TokenType + " " + accessToken.AccessToken); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent) { using (var reader = new System.IO.StreamReader(response.GetResponseStream())) { return reader.ReadToEnd(); } } return null; } public string Post(string url) { var accessToken = GetAccessTokenResponse(url); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.Method = "POST"; request.ContentLength = 0; request.Accept = acceptHeader; request.Headers.Add("Authorization", accessToken.TokenType + " " + accessToken.AccessToken); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent) { using (var reader = new System.IO.StreamReader(response.GetResponseStream())) { return reader.ReadToEnd(); } } return (null); } public string Merge(string url, Document doc) { var accessToken = GetAccessTokenResponse(url); var postData = new JObject { ["__metadata"] = new JObject { ["type"] = "SP.File" } }; foreach(string key in doc.MetaData.Keys) { postData.Add(key, doc.MetaData[key]); } byte[] listPostData = Encoding.ASCII.GetBytes(postData.ToString()); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.Method = "POST"; request.ContentLength = postData.ToString().Length; request.ContentType = contenttype; request.Accept = acceptHeader; request.Headers.Add("Authorization", accessToken.TokenType + " " + accessToken.AccessToken); request.Headers.Add("If-Match", "*"); request.Headers.Add("X-Http-Method", "MERGE"); Stream listRequestStream = request.GetRequestStream(); listRequestStream.Write(listPostData, 0, listPostData.Length); listRequestStream.Close(); HttpWebResponse response = (HttpWebResponse)request.GetResponse();