Saturday, May 16, 2015

API versioning in WEBAPI

API versioning is very common requirement of API developer. In the very initial stage you will require to share stubs and then later you have to maintain version. A very trivial and simple solution is to have different URL for different versions and have different handlers(controllers) for each.
Ofcourse the approch will work but there are features available in WebApi by which we can avoid having multiple URLs and make caller's life easy.
As we know that in MVC and WEBAPI, there is controller resolved which resolves the controller based on mapping. I will try to use the same thing to put our logic in between by which we can resolve the controller based on our logic.
For this first of all we need to create a controller selector -
public class CustomControllerSelector : DefaultHttpControllerSelector
{
private HttpConfiguration _config { get; set; }
public CustomControllerSelector(HttpConfiguration config) : base(config)
{
   _config = config;
}

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
}
}
In WebApi we DefaultHttpControllerSelector is the default Httpcontrollerselecotr. Here we have created our own selector and inheritied from Default one. DefaultControllerSelector has parametrized constructor which takes Httpconfiguration as input, so we will follow the same and here we have basic implementation in place.
Lets start writing something in SelectController, because this is the method which resolves the controller and returns HttpControllerDescriptor object.

1) lets get all the mapping availble in the application -
var controllers = GetControllerMapping();








If you see the screenshot, we get the mapping of Controller name with the actual controller object.

2) Get the parameters or routing info - var routeData = request.GetRouteData();
Based on the request URL, how it mapped with the mapping registered. For example if the following mapping is registered -
config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
then based on URL matched, what is the value of controller or id, we get this kind of values in the routeData.
3) Based on routeData, get he value of current controller -
 var controllername = (string)routeData.Values["controller"];

4) If we have followed attribute based mapping , then we will not get the controller named with above approach, hence we will just return the default mapping -
if (string.IsNullOrWhiteSpace(controllername))
            {
                return base.SelectController(request);
            }

5) Based on controller name, we can get the controller instance from the controller collection(step 1).
6) There are different ways of getting the version information from the URL- might be query parameter, or header. Here is the code of getting this version from query parameter -
        private string GetVersionFromQueryString(HttpRequestMessage request)
        {
            var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
            var version = query["ver"];

            if (version != null)
            {
                return version;
            }
            return "";

        }
7) once we have version we just have to form the name of controller accordingly and return the controller instance. Here is the example of version to be "stub", then we make the controller name as current controller + "_stub" and return it back -
string newName = string.Empty;
                if ("stub".Equals(version))
                {
                    newName = string.Concat(controllername, "_stub", "");

                    HttpControllerDescriptor versionedDescriptor;
                    if (controllers.TryGetValue(newName, out versionedDescriptor))
                    {
                        return versionedDescriptor;
                    }
                }

Here is the complete code for the reference  -
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
    var controllers = GetControllerMapping();
    var routeData = request.GetRouteData();
    var controllername = (string)routeData.Values["controller"]; // values determined by route
    HttpControllerDescriptor descriptor;
    if (string.IsNullOrWhiteSpace(controllername))
    {
return base.SelectController(request);
    }
    else if (controllers.TryGetValue(controllername, out descriptor))
    {
var version = GetVersionFromQueryString(request);
string newName = string.Empty;
if ("stub".Equals(version))
{
   newName = string.Concat(controllername, "_stub", "");

   HttpControllerDescriptor versionedDescriptor;
   if (controllers.TryGetValue(newName, out versionedDescriptor))
   {
return versionedDescriptor;
   }
}
return descriptor;
    }
    return null;
}

We just have to register this selector in our webapi config -
config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config));

Thats all, the versioning is done, you can write your own logic on which case you want to pass which controller instance. 

Saturday, May 9, 2015

Paging in WEBAPI

Lets talk about paging using webapi.There are multiple ways we can achieve pagination. We will talk about only 2 here -
1) OData :-
OData is liberary provided by Microsoft.
OData has its own query parameters and its data structure defined which can be used to achieve paging. Lot of details are given here –
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

Lets try to understand it using an example. Lets say i have a controller named ODataSample where i am implementing paging for a Get method.
public PageResult Get(ODataQueryOptions queryOptions)
{
    List returnValue = new List() { 
"1","2","3","4","5","6","7","8"
    };
    ODataQuerySettings settings = new ODataQuerySettings() { PageSize = 2 };
    IQueryable results = queryOptions.ApplyTo(returnValue.AsQueryable(),settings);
    return new PageResult(results as IEnumerable, Request.GetNextPageLink(), Request.GetInlineCount());
}

The above example implements simple paging using power of Odata. Lets start analyzing it one by one -
1) Query parameter - ODataQueryOptions - 
public PageResult Get(ODataQueryOptions queryOptions)
this the the query options where all the odata specific query parameters will be parsed. This class has method named as ApplyTo which will be used to filter the result based on query params passed.
2) settings - 
ODataQuerySettings settings = new ODataQuerySettings() { PageSize = 1 };
ODataQuerySetting is by which we can set the default page size. The same thing can be achieved by Attributes also.
3) ApplyTo - 
IQueryable results = queryOptions.ApplyTo(returnValue.AsQueryable(),settings);
apply the filter based on query parameter passed. By this method Odata is saving you from writing custom logic for the same.
4) Return type - PageResult
return new PageResult(results as IEnumerable, Request.GetNextPageLink(), Request.GetInlineCount());
PageResult is data structure provided by Odata library. 
GetNextPageLink generate the next page link whenever required. 
GetInlineCount will give you the number of items available.

lets try to analyze few sample URLs and their responses -
get 1 item, and count of all - 
http://localhost:52252/api/ODataSample?$top=1&$inlinecount=allpages
{"Items":["1"],"NextPageLink":null,"Count":8}

get 2 items and all count
http://localhost:52252/api/ODataSample?$top=2&$inlinecount=allpages
{"Items":["1","2"],"NextPageLink":null,"Count":8}

get 3 items and count - 
http://localhost:52252/api/ODataSample?$top=3&$inlinecount=allpages
{"Items":["1","2"],"NextPageLink":"http://localhost:52252/api/ODataSample?$top=1&$inlinecount=allpages&$skip=2","Count":8}
(only first page is returned and next page link is been provided)

get 1 item after skiping 2 - 
http://localhost:52252/api/ODataSample?$top=1&$inlinecount=allpages&$skip=2
{"Items":["3"],"NextPageLink":null,"Count":8}

get 5 items and count - 
http://localhost:52252/api/ODataSample?$top=5&$inlinecount=allpages
{"Items":["1","2"],"NextPageLink":"http://localhost:52252/api/ODataSample?$top=3&$inlinecount=allpages&$skip=2","Count":8}

If you observe we asked for 5 items and in the response we got 2 and next item link saying ask for $top=3 and skip 2 items. 
Once we hit it again we get – 
{"Items":["3","4"],"NextPageLink":"http://localhost:52252/api/ODataSample?$top=1&$inlinecount=allpages&$skip=4","Count":8}

Another 2 items and link for the last one – 
http://localhost:52252/api/ODataSample?$top=1&$inlinecount=allpages&$skip=4
which eventually returns - {"Items":["5"],"NextPageLink":null,"Count":8}

Whenever the request is not able to accommodate all data in the single response, w get the link of next page in it.

2) Custom :- In case of custom paging, we can follow the same design like OData followed. Based on some query parameter we can identify which page we need to send back. The easiest way to implement this is using LINQ.
Lets try to understand this approch using an example  -

public object Get(int page = 0)
{
    return GetAccounts(page,Request);          
}
const int PAGE_SIZE = 2;
private static object GetAccounts(int page, HttpRequestMessage request)
{
    var output = new string[] { "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8" };
    var result = output.Skip(PAGE_SIZE * page)
.Take(PAGE_SIZE);
    return new {
Results = result
    };
}

lets say we implement the Get method which take which page to return.
Using LINQ skip and Take method we can filter the result and return it back.

The basic requirement of pagination is done. Now we can make it more intutive for user to use it. For example, with above implementation no client will get to know how many pages are there, and also there is no way i can identify the URL of next/previous page.

Getting the total count -
var totalCount = output.Count();
    var totalPages = Math.Ceiling((double)totalCount / PAGE_SIZE);

Creating the link for next and previous page -
var helper = new UrlHelper(request);
    var prevUrl = page>0 ? helper.Link("DefaultApi", new { page = page - 1 }) : "";
    var nextUrl = page<totalPages-1 ?  helper.Link("DefaultApi", new { page = page + 1 }) : "";

helper take the route name and route value. Routename in this case is DefaultApi only and for previous page we need to pass page number 1 less than current, and for next page it will be 1 more than current.

Hence the final code for the same becomes -
private static object GetAccounts(int page, HttpRequestMessage request)
    var output = new string[] { "value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8" };
    var totalCount = output.Count();
    var totalPages = Math.Ceiling((double)totalCount / PAGE_SIZE);
    var helper = new UrlHelper(request);
    var prevUrl = page>0 ? helper.Link("DefaultApi", new { page = page - 1 }) : "";
    var nextUrl = page<totalPages-1 ?  helper.Link("DefaultApi", new { page = page + 1 }) : "";
    var result = output.Skip(PAGE_SIZE * page)
.Take(PAGE_SIZE);
    return new {
Pagination = new  {
   TotalCount = totalCount,
   TotalPages = totalPages,
   PrevPageUrl = prevUrl,
   NextPageUrl = nextUrl,
},              
Results = result
    };
}

Its good idea to pass all the pagination information in separate object, rather tahn combining it with the actual result.