Thursday, October 18, 2012

How to upload file using Resty.Net?

The bad news

Most of the REST clients comes with a built in mechanism to upload files. I also have plans to add such a feature in Resty.Net very soon, but as of now it doesn't have easy way to upload files.

The good news

If you are following Resty.Net for sometime then you may know that the goal of Resty.Net is to provide a powerful low level api making it just a thin layer above the HttpWebRequest class provided by dotnet, while also giving the highlevel goodness similar to other existing REST client libraries.

Due to its bare to the metal, low level nature, it is already possible to write codes to upload file using those low level features of Resty.Net. Most of the time if anything can be done through HttpWebRequest class, then it may also be possible to do same using Resty.Net. Here is an example of how you'd do it using the HttpWebRequest class http://www.dotnetthoughts.net/how-to-upload-file-using-httpwebrequest-class/

Ok, I got how to do it with HttpWebRequest. Show me how to do it with Resty.Net

Here is how:


string boundary = Guid.NewGuid().ToString();
RestRequest request = new RestRequest(HttpMethod.POST, new RestUri(_MyUri, "/File"));
request.ContentType = ContentType.MultiPartFormData.WithBoundary(boundary);

string[] files = new string[] 
{ 
"example1.jpg",
"example2.png"
};

IDictionary<string, string> formData = new Dictionary<string, string>
{
 {"Name", "nrip"},
 {"EmailAddress", "nrip@abc.com"},
};

StringBuilder sb = new StringBuilder();

foreach (var file in files)
{
 sb.AppendFormat("--{0}", boundary);
 sb.AppendFormat("\r\n");
 sb.AppendFormat("Content-Disposition: form-data; name=\"media\"; filename=\"" + Path.GetFileName(file) + "\"");
 sb.AppendFormat("\r\n");
 sb.AppendFormat("Content-Type:  " + MimeTypes.GetMimeType(Path.GetExtension(file)) ?? ContentType.ApplicationOctetStream.ToString());
 sb.AppendFormat("\r\n");
 sb.AppendFormat("\r\n");
 using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
 {
  byte[] contents = new byte[fs.Length];
  fs.Read(contents, 0, contents.Length);
  sb.Append(Encoding.Default.GetString(contents));
 }
 sb.AppendFormat("\r\n");
}

foreach (var keyvaluepair in formData)
{
 sb.AppendFormat("--{0}", boundary);
 sb.AppendFormat("\r\n");
 sb.AppendFormat("Content-Disposition: form-data; name=\"" + keyvaluepair.Key + "\"");
 sb.AppendFormat("\r\n");
 sb.AppendFormat("\r\n");
 sb.AppendFormat(keyvaluepair.Value);
 sb.AppendFormat("\r\n");
}

sb.AppendFormat("--{0}--", boundary);
byte[] fulldata = Encoding.Default.GetBytes(sb.ToString());

var body = new RestRawRequestBody(fulldata);
request.Body = body;

//Actual posting of body content will occure herer
var response = request.GetResponse();

Most of the part would be very comparable to the original post, constructing the multi-part form data structure. Resty.Net has a Body type called RestRawRequestBody, which takes raw byte array (byte[]) as the body content. Body content are sent to the server, obviously putting them in the Request body. I'll discuss more on other RestBodies available in Resty.Net in future. For now I think the above capability of Resty.Net makes my point clear, the RestRequest class can be utilized to do most of task that can be done through HttpWebRequest. I would dare to put it numerically that 90% of work that can be done using HttpWebRequest can also done using RestRequest of Resty.Net

Wednesday, October 17, 2012

Testing REST clients

Problem

While writing code for Resty.Net I had a problem about how should I deal with the tests. Well I could easily write tests for most of the parts but, I got stock at writing test for the RestRequest class. I thought I could mock RestRequest with a fake implementation. But mocking wouldn't be a solution for my situation. Mocking would have been the perfect solution if I was using Resty.Net in another project, and testing that project. As I'm trying to test if RestRequest itself is implemented correctly or not, mocking RestRequest wasn't the solution.

I thought about mocking the underlying HttpWebRequest, but wasn't quite satisfied with it too.

Search for solution

I did what most of person in the above situation would usually do, I "Googled". After googling for sometimes, changing my keyword combinations and scanning through many pages I finally found a good enough solution at CSharp On The Fritz. Here is the link to the exact post I'm talking about: http://www.csharpfritz.com/post/26765731081/restful-client-unit-testing-with-nancyfx. Yeah, it suggests a neat idea of using embedded NancyFx server and making requests against that server.

The solution

Once I got the inspiring idea of using NancyFx for testing, I did what most of the lazy coders would do, i.e I copied the code at http://www.csharpfritz.com/post/26765731081/restful-client-unit-testing-with-nancyfx, and began writing tests. All went quite well for sometime, then as the number of tests increased the tests began to fail. The problem was, the port sometimes didn't get released by a previous tests, while the new test was already running. Now, I had to make changes to the basic code that I had CTRL+Ced and CTRL+Ved.

Here's my solution:

public class NancyHostHelper
{
 protected Uri _uri = new Uri("http://localhost:50001");
 private NancyHost _Nancy;
 private static int port = 50001;

 public Uri Start()
 {
  bool nancyStarted = false;
  // Need to retry in order to ensure that we properly startup after any failures
  for (var i = 0; i < 3; i++)
  {
   _Nancy = new NancyHost(_uri);

   try
   {
    _Nancy.Start();
    nancyStarted = true;
    break;
   }
   catch (HttpListenerException)
   {
    UriBuilder ub = new UriBuilder(_uri);
    ub.Port = ++port;
    _uri = ub.Uri;
   }
   catch
   {
    try
    {
     _Nancy.Stop();
    }
    catch (Exception e)
    {
    }
   }
  }

  if (!nancyStarted)
  {
   //Don't allow to run the tests if Nancy not started.
   throw new Exception();
  }

  return _uri;
 }

 public void Stop()
 {
  try
  {
   _Nancy.Stop();
   _Nancy = null;
  }
  catch { }
 }
}
Well the solution as you can see above is:
  • Increment the port number and,
  • Try restarting the server again, at new incremented port number.

You, can see the practical usage of the above class in the github repository for Resty.Net at https://github.com/nripendra/Resty.Net/blob/master/tests/Resty.Net.Tests/RestRequestTest.cs.

So far its working quite well, I'll keep updating this blog if anything comes up that makes it necessary to make other changes to the above code.

Saturday, October 13, 2012

RestUri in Resty.Net

Uris are very much basic part of the whole REST conceptual model, the Uniform Resource Locator (Uri) points to a unique resource. REST is all about performing operation on those resources. The RestUri class in Resty.Net is divided into mainly two parts:
  1. The Base Uri.
  2. The Resource Uri

The Base Uri:

The base Uri points the server where the REST resources exists. eg: http://localhost/ , https://localhost/ , https://locahost:50001 , etc. 

The Resource Uri:

The resource Uri points to the resource on the server. e.g. /Person, /Person/1, /book etc. The resource uri can be resource template which has variables embedded, e.g. /Person/{id}

API documentation:


Constructors:
  • RestUri(string baseUri)
    • Instantiate a RestUri with the complete url in a single string. 
      • e.g new RestUri("http://example.com/Person/{id}");
  • RestUri(string baseUri, string resourceUri)
    • Instantiate a RestUri with base url set to baseUri and the resource uri template set to resourceUri.
      • e.g. new RestUri("http://example.com","/Person/{id}");
  • RestUri(Uri baseUri, string resourceUri)
  • RestUri(Uri baseUri, Uri resourceUri)

Methods:
  • SetQuery(string name, object value)
    • Set a querystring parameter for the RestUri instance. Returns the current instance of RestUri hence making it possible to chain the methods in fluent manner.
      • e.g. new RestUri("http://example.com","/Person").SetQuery("searchTerm", "bob")
      • => http://example.com/Person?searchTerm=bob
  • SetQuery(object queryParams)
    • Set a querystring parameter for the RestUri instance. Returns the current instance of RestUri hence making it possible to chain the methods in fluent manner.
      • e.g. new RestUri("http://example.com","/Person/{id}").SetQuery(new { searchTerm = "bob"})
      • => http://example.com/Person?searchTerm=bob
  • SetParameter(string name, object value)
    • Set uri template parameter value.
      • e.g. new RestUri("http://example.com","/Person/{id}").SetParameter("id", 1)
      • => http://example.com/Person/1
  • SetParameter(object uriTemplateParams)
    • Set uri template parameter value.
      • e.g. new RestUri("http://example.com","/Person/{id}").SetParameter(new {id = 1})
      • => http://example.com/Person/1

Properties:
  • BaseUri
    • Gets the base uri of a request.

Setting multiple querystrings


Fluent style:
new RestUri("http://example.com","/Person")
        .SetQuery("searchTerm", "bob")
        .SetQuery("page",1)
        .SetQuery("perpage", 10);
=> http://example.com/Person?searchTerm=bob&page=1&perpage=10

Anonymous style:
new RestUri("http://example.com","/Person")
        .SetQuery(new {searchTerm = "bob", page= 1,perpage=10});
=> http://example.com/Person?searchTerm=bob&page=1&perpage=10

Setting multiple template parameters


Fluent style:
new RestUri("http://example.com","/Person/{searchTemr}/{page}/{perpage}")
        .SetParameter("searchTerm","bob")
        .SetParameter("page", 1)
        .SetParameter("perpage", 10);
=> http://example.com/Person/bob/1/10

Anonymous style:
new RestUri("http://example.com","/Person/{searchTemr}/{page}/{perpage}")
        .SetParameter(new{searchTerm = "bob", page= 1,perpage=10});
=> http://example.com/Person/bob/1/10

How RestUri sits together with RestRequest?

RestUri restUri = new RestUri("http://example.com","/Person/{searchTemr}/{page}/{perpage}").SetParameter(new{searchTerm = "bob", page= 1,perpage=10});
RestRequest request = new RestRequest(HttpMethod.Get, restUri);

Monday, October 8, 2012

Introducing Resty.Net

Well it's been very long since I last blogged, I was waiting to stumble some new experience worth sharing. Today I'd like to introduce my first ever open source project Resty.Net hosted in github.

So what is Resty.Net?

Resty.Net is a simple bare to metal REST/HTTP client for .net framework written in c#. It serves as a very thin layer above the HttpWebRequest object and exposes most of the properties available in HttpWebRequest.

Why another Rest client?

It's true that there are many rest clients for dotnet framework. I have used the HttpClient from microsoft, I have also used another mature and inspirational and superb Restsharp library. I have liked both of them quite well. But I needed something quite lightweight, and something that gave me more control over the underlying HttpWebRequest. In fact I wanted to use HttpWebRequest directly but with all the strongly typed supports and the API goodness that HttpClient and RestSharp provided. So, the result is Resty.Net.

Well I had been planning for an open-source project for a long time, but the dream hadn't materialized till now, so when I created this rest client, I thought about open sourcing it.

Some examples.

RestRequest request = new RestRequest(HttpMethod.GET, new RestUri("http://example.com/api", "/Person/{id}").SetParameter("id", "1"));

request.AddHeader(new { header = "value" });
request.AddHeader("header2", "value");

using (RestResponse response = request.GetResponse())
{
  var contentStream = response.Body.ReadAsStream();
  var contentByteArray = response.Body.ReadAsByteArray();
  string contentString = response.Body.ReadAsString();
}

//strongly typed response
RestRequest request2 = new RestRequest(HttpMethod.GET, new RestUri("http://example.com/api", "/Person/{id}").SetParameter("id", "2"));

request.AddHeader(new { header = "value" });
request.AddHeader("header2", "value");

using (RestResponse<person> response = request.GetResponse<person>())
{
  var person = response.Data;
  var email = person.Email;
}

I think the API itself is quite clear, create a RestRequest instance and call it's GetResponse method to send the request to server and get the response from server. RestRequest constructor takes two arguments:
  • The HttpMethod
  • The RestUri.
These two are very important and most basic concepts in Rest apis. To send the content to server (e.g. inPOST method) the Body property must be set. Next thing is to call GetResponse method, which will return an instance of RestResponse. GetResponse also has a strongly typed overload, which will return strongly typed RestResponse and that's it.

Give me Restsharp like RestClient.

If you prefer a RestSharpis api more, then RestInvoker class under Rest.Net.Extras namespace is just the thing for you.
using Rest.Net.Extras;
.
.
.
RestInvoker invoker = new RestInvoker();
RestResponse response invoker.Get(new RestUri("http://example.com/api", "/Person/{id}").SetParameter("id", "2"));

Where is my Fluent API?

The RestRequestBuilder class under Rest.Net.Extras gives you a way to build RestRequest with fluent API.
using Rest.Net.Extras;
.
.
.
RestRequest request = RestRequestBuilder.CreateRequest(HttpMethod.Get, new RestUri("http://example.com/api", "/Person/{id}").SetParameter("id", "2"))
        .WithHeader("accept","application/json")
        .WithHeader("header2","value")
        .WithCookie("cookie1","value");

Where to get it?

Of course in GitHub https://github.com/nripendra/Resty.Net, you can fork it or just clone it locally, and if feeling generous you can also contribute to the project.

I have also uploaded a prelease nuget package at http://nuget.org/packages/Resty.Net/1.0.1-beta.
Since, I have designeted it as a prerelease, -pre flag must be included in nuget install-package command.
Install-Package Resty.Net -Pre

"Include Prelease" dropdown options must be selected when using Nuget package manage GUI or even searching package in nuget.org.

Finally

I have tried to follow principles like DRY, and open-close as far as I understood them. It is by no means complete product and likely to change a lot. I'll try to find time for posting more Resty.Net features in future, and also keep on improving it.