Pragmatic Restfull API with ASP C#’S Web API

6 Jan

Recently I had to write an API to an existing ASP C# web application. It was an interesting experience of which I would love to share my experience with the hope that I might help a few and also get advised on some aspects.

When designing the API architecture; I had to make a choice on the framework (SOAP or REST), the message format to use (JSON or XML) and which of the two to use Web API or WCF.

After consulting and getting the green light from some of my more experienced workmates I chose to go with XML running over REST in Web API. After analyzing this comparison between Web API andWCF, I decided to go with Web API because it was purely designed with REST in mind and was ideal for what I intended to build.

Why Pragmatic REST
I have tried to read extensively about REST best practices from various sources but it seems there is no official or recognized REST best practices but instead most developers go with what works, is flexible, is robust and to a large extents meets Roy Fielding’s dissertation on REST.
I tried to conform to some of REST’s standards in my approach to the design while in some areas I slightly veered off.

Below is how I approached my small REST project, with emphasis on a few areas I found interesting.

Resource Definition
I used four resources (api/CustomerVerification), (api/TransactionStatus), (api/MakeTransaction), (api/ReverseTransaction all accepting only POST requests.
Each was in its own controller with a Post method ie public HttpResponseMessage Post(HttpRequestMessage request).

Data handling
Initially I tried out parameter binding where by an incoming request was bound to a corresponding model. Ie public HttpResponseMessage Post(HttpRequestMessage request, CustomerInfoRequest cust). Here the Post action expects the incoming XML message body to be deserialized to type CustomerInfoRequest . (The message format is set in the API specification contract)

1
2
3
<CustomerInfoRequest>
    <CustReference></CustReference>
</CustomerInfoRequest>
1
2
3
public class CustomerInfoRequest{
     public string CustReference { get; set; }
}

To enable serializing and deserializing of incoming and outgoing requests from xml to the corresponding objects and vice versa, I took advantage of System.Runtime.Serialization features.
For example the CustomerInfoRequest model class used the System.Runtime.Serialization namespace to have its class decorated with a DataContract attribute and its members decorated with aDataMember attribute. The DataContract attribute allows the class to be serializable by  DataContractSerializer and the DataMember specifies that the member is part of a data contract and is serializable by DataContractSerializer.

1
2
3
4
5
6
[DataContract(Namespace = "")]
public class CustomerInfoRequest
{
     [DataMember(IsRequired = true)]
     public string CustReference { get; set; }
}

[DataContract(Namespace = “”)] allows for namespace definition, If you leave out the Namespace=””, a default namespace will be created by Web API matching the path to your model class which I think is ugly. Requests without this namespace will fail so unless there is a specific namespace to be used I preferred leaving the namespace empty (Namespace=””).

The issue I encountered with the above parameter binding method was that the DataContractSerializer cares a great deal about the element ordering. Elements have to be ordered in alphabetical order ie <name> should come after <address> or an exception will be thrown. I ditched parameter binding and instead opted to deserialize the XML request to the corresponding model class using the less emotionalXmlSerializer.

So our controller’s Post method now changed into:

Data validation
When creating the class models each of the properties’ was appropriately decorated with the required data annotations using System.ComponentModel.DataAnnotations class ie

1
2
3
[DataType(DataType.Text)]
[StringLength(51, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 4)]
public string CustReference { get; set; }

The data restrictions are got from the API specification document created early on at project inception. All incoming requests are be checked to ensure the request message matches the required specification. This can be done by using the ValidationContext class to validate the request model against the specified data annotations on each of the model members

All requests are validated with the above method in the controller ie ParameterHelper.ValidateApiRequestData(custReqestInfo);

Security
There are quite many ways on how to implement Rest API security and in my opinion there is no agreed right way of doing it at least for now. Hence different people have different ways of implementing API security. In my case I utilized both an API key and a hashed value sent as part of the request.

1
2
3
4
5
<CustomerInfoRequest
    <HashedValue></HashedValue>
    <ApiKey></ApiKey>
    <CustReference></CustReference>
</CustomerInfoRequest>

The API key uniquely identifies the requesting third party while the HashedValue is created by hashing a concatenation of a private key (provided to the third party) and a few other values like time using the SHA51 algorithm.
For some requests like (api/MakeTransaction) the HashedValue is unique to each request .
On top of the above, incoming requests are sent over https with IP blocking in place (only requests from recognizable IP addresses are allowed).
For now I think this is a bit secure but I could be wrong…….

Request & Response Logging
This was a bit tricky but reading this article greatly helped. Briefly, the blog post describes the use of a message handler to handle all incoming and outgoing requests. I also took advantage of Elmah’s error logging features.

Exception Handling
I created a master Exception class (ServiceException) through which formatted error output was sent back to the calling party.
All kinds of exceptions encountered in the application were caught and then thrown again as a custom exception of type ServiceException. This way all exceptions can be categorized and sent back with meaningful data

There is a final try catch in the controller class to catch all thrown ServiceException

1
2
3
4
5
6
7
8
9
try{.........}
 catch (ServiceException e)
 { return Request.CreateResponse(HttpStatusCode.OK, e.FormatResponse());}
 catch (Exception e) //to handle any unhandled exceptions in the application
 {
      ServiceException pd = new ServiceException();
      pd.ExceptionMessage = e.Message;
      return Request.CreateResponse(HttpStatusCode.InternalServerError, pd.FormatUnhandledResponse());
 }

This post is mostly rudimentary but hopefully something good will come out of it.

Source: http://kedyr.wordpress.com/2014/01/04/pragmatic-restfull-api-with-asp-cs-web-api/

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

%d bloggers like this: