Extending SharePoint 2013’s REST _api endpoints – write operations with POST

Hi,

If you haven’t read my previous post on this topic, please go read http://www.silver-it.com/node/160 it since I’m only going to focus on the write operations here. As you know, in REST, whenever you want to create a resource, you should use the HTTP POST verb.In my previous post, I explained how to handle ComplexTypes and Collections with HTTP GET using your own _api endpoints in SharePoint 2013. These operations were all READ operations based on HTTP GET.
To declare a method that can only be called by HTTP POST, you need to implement the following methodinformation:

MethodInformation m0 = new MethodInformation
{
    Name = "PostMethod",
    IsStatic = false,
    OperationType = OperationType.Default,
    ClientLibraryTargets = ClientLibraryTargets.All,
    OriginalName = "PostMethod",
    WildcardPath = false,
    ReturnType = typeof(void),
    ReturnODataType = ODataType.Invalid,
    RESTfulExtensionMethod = false,
    ResourceUsageHints = ResourceUsageHints.None,
    RequiredRight = ResourceRight.Default
};
m0.Parameters.Add(new ParameterInformation
{
    Name = "p1",
    RESTfulParameterSource = RESTfulParameterSource.Default,
    ParameterType = typeof(string),
    ParameterODataType = ODataType.Primitive,
    IsOptional = false,
    DefaultValue = null
});           

yield return m0;

What is important here is the OperationType attribute that must be set to OperationType.Default.. The other value is OperationType.Read which implicitely allows the HTTP GET. With OperationType.Default, SharePoint knows that he shoudln’t allow that method to be called via HTTP GET but that’s not enough! To enforce it, you need to explicitely tell SharePoint to control the method when invoking it:

switch (methodName)
{
    case "Empty":
        isVoid = true;
        return null;
    case "PostMethod":
        isVoid = true;
        this.CheckBlockedMethod("PostMethod", proxyContext);
        PostMethod_MethodProxy(target, xmlargs, proxyContext);
        return null;
}

So, the important bits here are the call to the base method CheckBlockedMethod. If you omit this guy, SharePoint will allow HTTP GET over that method although you specified OperationType.Default in the method information. In this case I’m returning null but of course, if you have a return value, you should return it as usual. The proxy looks like what we’ve seen in my previous post:

private static void PostMethod_MethodProxy(object target, ClientValueCollection xmlargs, ProxyContext proxyContext)
{
    SilverIT me = target as SilverIT;
    me.PostMethod(
        Microsoft.SharePoint.Client.ServerStub.GetArgument(xmlargs, 0).ConvertTo<string>());
}

So here you retrieve the arguments as for a HTTP GET method. Now, if you try to call that method with the browser, you’ll get the following error message reported by SharePoint:

The HTTP method 'GET' cannot be used to access the resource 'TestMethod'. The operation type of the resource is specified as 'Default'. Please use correct HTTP method to invoke the resource.

So, that’s exactly what we need here. Here is a piece of code that shows how to invoke our POST method in JavaScript from an HTML page located in the TEMPLATE/LAOUTS folder:

$.ajax({
    url: "/_api/contextinfo",
    type: "POST",
    contentType: "application/x-www-url-encoded",
    headers:{"Accept":"application/json; odata=verbose"},
    success: function (data) {
     if(data.d)
     {
      $.ajax({
        url: "/_api/silverit/TestMethod",
        headers:
          {"Accept":"application/json; odata=verbose",
           "x-requestdigest": data.d.GetContextWebInformation.FormDigestValue,
            "x-requestforceauthentication": true
          },
        type:"POST",
        contentType:'application/json; odata=verbose',
        data:JSON.stringify({ 'p1': 'test' }),
        success: function (d) {
            console.log("ok");
        },
        failure: function (errMsg) {
            console.log(errMsg);
        }
      });
     }
    },
    error: function (xhr) {
     console.log(xhr.status + ': ' + xhr.statusText);
    }
});

The first request consists in getting the DIGEST that’s required to consume _api endpoints in HTTP POST. When the first request completes, I make a call to my own function. I’m passing the DIGEST and a JSON object to it. Note that alternatively, you can also call your function as in a GET request like this “/_api/silverit/TestMethod(p1=’value’)” but usually one prefer to pass a JSON object via the data property

Happy Coding!

Advertisements

About Stephane Eyskens

Office 365, Azure PaaS and SharePoint platform expert
This entry was posted in SharePoint and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s