Thursday, June 28, 2012

SData JSON Payloads & MVC .NET Web API

In a previous post I discussed handling SData URLs in MVC .NET Web API. It’s easy to support most of the SData query language in a Web API project if you use my SDataHandler library. The SDataHandler class library is a POC I’ve developed to illustrate how to add SData support to MVC .NET Web API projects.

The SDataHandler class provides/returns JSON payloads including some of the metadata specified by SData 2.0 specification. I should note the SData 2.0 specification has not been ratified yet so some of this might change a bit in the final SData 2.0 release.

If you’re not familiar with JSON or JSON in SData here’s a quick overview of how we represent data in SData with JSON:

A simple Customer object with following structure and values:

customername -> American Business Futures
addressline1 -> 123 Main Street
city -> Milwaukee
state -> WI
zipcode -> 90210
telephoneno -> (414) 555-4787
openorderamt -> 0

A JSON representation of this Customer would look something like:

“Customer”:
{
           "customername": "American Business Futures",
           "addressline1": "2131 N. 14th Street",
           "city": "Milwaukee",
           "state": "WI",
           "zipcode": "53205-1204",
           "telephoneno": "(414) 555-4787",
           "openorderamt": 0
}

A collection of Customers would be returned as a JSON array, so if a client requests a list of all Customers the payload returned would look like this:

{
  "$resources":
   [
       {
           "customername": "American Business Futures",
           "addressline1": "2131 N. 14th Street",
           "city": "Milwaukee",
           "state": "WI",
           "zipcode": "53205-1204",
           "telephoneno": "(414) 555-4787",
           "openorderamt": 0,
       },
       {
           "customername": "Dell Computers",
           "addressline1": "1st street",
           "city": "Irvine",
           "state": "CA",
           "zipcode": "92614",
           "telephoneno": "(414) 555-1234",
           "openorderamt": 0,
       },
       {
           "customername": "Jaretts Hardware",
           "addressline1": "2nd street",
           "city": "Irvine",
           "state": "MI",
           "zipcode": "92614",
           "telephoneno": "(414) 555-5678",
           "openorderamt": 0,
       }
]}

Notice the “$resources” array in the payload, SData keywords within the payload always start with a “$”. SData allows services to provide additional metadata like paging information, etc., along with the payload too. If you’re not familiar with paging in SData see the paging section of the SData web site 

An SData collection payload with paging metadata like counts, and links would look like this:

{
   "$totalResults": 1,
   "$startIndex": 1,
   "$itemsPerPage": 26,
   "$next": "http://localhost:1698/sdata/Customers",
   "$previous": "",
   "$first": "http://localhost:1698/sdata/Customers",
   "$last": "http://localhost:1698/sdata/Customers",
   "$resources":
   [
       {
           "customername": "American Business Futures",
           "addressline1": "2131 N. 14th Street",
           "city": "Milwaukee",
           "state": "WI",
           "zipcode": "53205-1204",
           "telephoneno": "(414) 555-4787",
           "openorderamt": 0,
       },
       {
           "customername": "Dell Computers",
           "addressline1": "1st street",
           "city": "Irvine",
           "state": "CA",
           "zipcode": "92614",
           "telephoneno": "(414) 555-1234",
           "openorderamt": 0,
       },
       {
           "customername": "Jaretts Hardware",
           "addressline1": "2nd street",
           "city": "Irvine",
           "state": "MI",
           "zipcode": "92614",
           "telephoneno": "(414) 555-5678",
           "openorderamt": 0,
       }
]}

Typically SData providers will also return information like the URL for this collection/resource and an entry might also indicate a key. E.G:

{
   "$baseurl": "http://localhost:1698/sdata/Customers",
   "$totalResults": 1,
   "$startIndex": 1,
   "$itemsPerPage": 26,
   "$next": "http://localhost:1698/sdata/Customers",
   "$previous": "",
   "$first": "http://localhost:1698/sdata/Customers",
   "$last": "http://localhost:1698/sdata/Customers",
   "$resources":
   [
       {
           "customername": "American Business Futures",
           "addressline1": "2131 N. 14th Street",
           "city": "Milwaukee",
           "state": "WI",
           "zipcode": "53205-1204",
           "telephoneno": "(414) 555-4787",
           "openorderamt": 0,
           "$url": "Customer(303130303030303035)",
           "$key": "303130303030303035"
       },
       {
           "customername": "Dell Computers",
           "addressline1": "1st street",
           "city": "Irvine",
           "state": "CA",
           "zipcode": "92614",
           "telephoneno": "(414) 555-1234",
           "openorderamt": 0,
           "$url": "Customer(303130303030303033)",
           "$key": "303130303030303033"
       },
       {
           "customername": "Jaretts Hardware",
           "addressline1": "2nd street",
           "city": "Irvine",
           "state": "MI",
           "zipcode": "92614",
           "telephoneno": "(414) 555-5678",
           "openorderamt": 0,
           "$url": "Customer(303130303030303036)",
           "$key": "303130303030303036"
       },

The SDataHandler class will decorate your model and add this metadata to payloads return by your Web API project. As indicated in my post on SData URLs in MVC .NET Web API you can download and add my SDataHandler class to a Web API project and it will add support for SData queries and JSON payloads.

The source code and a build of Sage.SDataCommon is available on GitHub. Download the Sage.SDataCommon.dll from GitHub

Then just add a reference to the Sage.SDataCommon in your Web API project, and add the following code to your project's Global.asax.cs:
using Sage.SData.CommonComponents;
In the "Application_Start()" method somewhere after the Registering the routes add the following one line of code:

GlobalConfiguration.Configuration.MessageHandlers.Add(new SDataTransformHandler());
The "Application_Start()" method should look like:
protected void Application_Start()
{
 ....
        RegisterRoutes(RouteTable.Routes);
        GlobalConfiguration.Configuration.MessageHandlers.Add
new SDataHandler());
 ...
}


Now run your Web API service, open it in a web browser and request a resource. The SDataHandler class will return SData 2.0 JSON.

1 comment: