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.

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();


        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 PostDocument(string url, byte[] document) {
        var accessToken = GetAccessTokenResponse(url);

        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
        request.Method = "POST";
        request.ContentLength = document.Length;
        request.ContentType = contenttype;
        request.Accept = acceptHeader;
        request.Headers.Add("Authorization", accessToken.TokenType + " " + accessToken.AccessToken);

        Stream listRequestStream = request.GetRequestStream();
        listRequestStream.Write(document, 0, document.Length);
        listRequestStream.Close();

        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);
    }


    private OAuth2AccessTokenResponse GetAccessTokenResponse(string url) {
        Uri targetWeb = new Uri(url);
        string targetRealm = TokenHelper.GetRealmFromTargetUrl(targetWeb);
        var responseToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, targetWeb.Authority, targetRealm, ClientId, ClientSecret);

        return responseToken;
    }
}

The handler adds all the correct headers to the specific Http methods and returns the results of the API calls. The complete source code including a console application for testing can be downloaden from here:

Related Posts

Part 3 – Console application to call a API with Azure Active Directory Aut... This post is the third and last in a series of three posts and will help you with the creation of identity pass-through authentication from a client a...
Securing an API app with an Application Identity – Part 2 In the previous post the API app was configured and altered to support Application Identity security. The next step is to make a client application re...
Securing an API app with an Application Identity–Part 1 Deploying an API within Azure is a very simple tasks. But how about security? The API itself is exposed to the outside world. When for example have a ...
User automatically removed from SharePoint Group During my current project we received an access request from a user. We did what we normally do, we checked the request and added the user in the appr...
Warm Up Form Based Web Application Normal warm up scripts for SharePoint open a site object or web object and make a request to that specific site. When you use form based authenticatio...
Load modules by default when opening PowerShell At the moment we are working a lot with PowerShell in combination with SharePoint. Over time we created a lot of usable functions that were not availi...

Leave a Reply

Your email address will not be published. Required fields are marked *