Pattern for Consuming REST Services (ASP.NET Web API) from a .NET Client (Using HttpClient)
RESTful Service Server-Side is the most common feature in Micro-services software architecture. It would be best to design a pattern to consume data so that we can use this for any RESTful Service.
For Simplicity, In this article I have used .Net client application which is consume movie data from OMDB API http://www.omdbapi.com/.
BaseClient Class
First, We need to define the base client class which provides a generic interface to deserialize the data from given API URL. Notice that the Main Extarcting data function as an async method named ExtractDataFromAPI and then await until it completes. Many of the HttpClient methods are async, because they perform network I/O.
public class BaseClient
{
protected readonly UriBuilder _uriBuilder;
protected readonly string _endpoint;
public BaseClient(string endpoint)
{
_endpoint = endpoint;
_uriBuilder = new UriBuilder(_endpoint);
}
protected async Task<T> ExtractDataFromAPI<T>(string queryString)
{
using (var httpClient = new HttpClient())
{
_uriBuilder.Query = queryString;
HttpResponseMessage response = await httpClient.GetAsync(_uriBuilder.ToString());
using (HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(result);
}
}
}
}
Implement Omdb Client
So, Lets Implement all the client services which inherits from Base Client. To implement base client we need to pass constructor parameter called endpoint as API Base URL here. Also to retrieve data from ExtractDataFromAPI, need to pass query string.
For example http://www.omdbapi.com/?s=bat&r=json
end point - http://www.omdbapi.com/
query string - ?s=bat&r=json
public class OmdbRequestService : BaseClient, IOmdbRequestService
{
// Also we can keep this api string web config App setting
public const string omdbUrl = "http://www.omdbapi.com/?";
public OmdbRequestService()
: base(omdbUrl)
{
}
// Omdb Request goes here
// Created some request like SearchMovie, GetMovieByIMDBId, GetMovieByTitle
// We can create more in future Example - GetMovieByIMDBIdAndYear, GetMovieByTitleAndPlot, etc
public Task<MovieSearchList> SearchMovie(string search)
{
// async method, client can use await
// query string builded from OmdbQueryBuilder
return ExtractDataFromAPI<MovieSearchList>(OmdbQueryBuilder.QueryBySearchDataTypeJson(search));
}
public Task<Movie> GetMovieByIMDBId(string imdbID)
{
return ExtractDataFromAPI<Movie>(OmdbQueryBuilder.QueryByImdbIdDataTypeJson(imdbID));
}
public Task<Movie> GetMovieByTitle(string title)
{
return ExtractDataFromAPI<Movie>(OmdbQueryBuilder.QueryByTitleDataTypeJson(title));
}
}
Here, I created a small OmdbQueryBuilder static class to build query strings. It is simple
// Build QueryString for Url
// Future - Refactor this with NameValueCollection
public static class OmdbQueryBuilder
{
private const string SEARCH= "s";
private const string TITLE = "t";
private const string IMDB_ID = "i";
private const string DATA_TYPE= "r";
private const string JSON= "json";
private const string XML = "xml";
public static string QueryBySearchDataTypeJson(string search)
{
return SEARCH + "=" + search + "&" + DATA_TYPE + "=" + JSON;
}
public static string QueryByImdbIdDataTypeJson(string imdbId)
{
return IMDB_ID + "=" + imdbId + "&" + DATA_TYPE + "=" + JSON;
}
public static string QueryByTitleDataTypeJson(string title)
{
return TITLE + "=" + title + "&" + DATA_TYPE + "=" + JSON;
}
}
Complete Code Example
Here is the GitHub Link (https://github.com/jayakaran1987/Consuming-RESTful-Service-HttpClient) for complete code for this article. It is an implemented web application that makes use of http://www.omdbapi.com/ API that performs the following:
- Allow the user to search for any movie(s) they want.
- Search results are presented in a grid/table format
I have used the following Technology Stack
- C# and .NET MVC for a web application
- AngularJS
- Telerik/Kendo Controls
- HTML 5 , Javascript & Jquery
- Bootstrap