Chapter 2. RestTemplate

Invoking RESTful services in .NET is typically done using the HttpWebRequest class. For common REST operations this approach is too low level as shown below.

/*
 * long-hand approach necessary to access HTTP endpoints without benefit of RestTemplate...
 */

Uri address = new Uri("http://example.com/hotels/1/bookings");

HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
string requestBody = // create booking request content

byte[] byteData = UTF8Encoding.UTF8.GetBytes(requestBody);
request.ContentLength = byteData.Length;
using (Stream requestStream = request.GetRequestStream())
{
  requestStream.Write(byteData, 0, byteData.Length);
}

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
  if (response.StatusCode == HttpStatusCode.Created)
  {
    string location = response.Headers["Location"];
    if (location != null)
    {
      Console.WriteLine("Created new booking at: " + location);
    }
  }
}
[Note]Note

There is also another class in the .NET framework, WebClient, that might also be considered for this long-hand approach but its lack of support for HTTP headers and HTTP status codes/descriptions generally makes it unsuitable for use in these kinds of broader HTTP interactions.

RestTemplate provides higher level methods that correspond to each of the six main HTTP methods that make invoking many RESTful services a one-liner and enforce REST best practices.

2.1. REST operations

Table 2.1. Overview of RestTemplate methods

The two other methods mentioned take URI template arguments in two forms, either as a object variable length argument or an IDictionary<string, object>.
For example,

// using variable length arguments
string result = restTemplate.GetForObject<string>("http://example.com/hotels/{hotel}/bookings/{booking}", 42, 21);

// using a IDictionary<string, object>
IDictionary<string, object> vars = new Dictionary<string, object>(1);
vars.Add("hotel", 42);
string result = restTemplate.GetForObject<string>("http://example.com/hotels/{hotel}/rooms/{hotel}", vars);

The names of RestTemplate methods follow a naming convention, the first part indicates what HTTP method is being invoked and the second part indicates what is returned. For example,

  • The method GetForObject<T>() will perform a GET, and return the HTTP response body converted into an object type of your choice.

  • The method PostForLocation() will do a POST, converting the given object into a HTTP request and return the response HTTP Location header where the newly created object can be found.

  • The method PostForMessage<T>() will do a POST, converting the given object into a HTTP request and return the full HTTP response message composed of the status code and description, the response headers and the response body converted into an object type of your choice.

The request object to be POSTed or PUTed, may be a HttpEntity instance in order to add additional HTTP headers. An example is shown below.

Booking requestBody = // create booking request content
HttpEntity entity = new HttpEntity(requestBody);
entity.Headers["MyRequestHeader"] = "MyValue";

template.PostForLocation("http://example.com/hotels/{id}/bookings", entity, 1);
[Note]Note

These operations are synchronous and thus are not available for Silverlight and Windows Phone because all related network calls have to be asynchronous.

2.1.1. Asynchronous operations

All REST operations may also be invoked asynchronously as well.
The asynchronous methods are suffixed by the word 'Async' based on common .NET naming conventions.


Although asynchronous call were designed to support Silverlight and Windows Phone, asynchronous invocation can also be used for Windows Forms and WPF applications, etc. to avoid blocking the UI when invoking RESTful services.
An example using an asynchronous method is shown below :

template.GetForObjectAsync<string>("http://example.com/hotels/bookings", 
  r =>
  {
    if (r.Error != null)
    {
      Console.WriteLine(r.Error);
    }
    else
    {
      Console.WriteLine(r.Response);
    }
  });

2.1.2. Asynchronous operations using the Task Parallel Library (TPL)

[Since 1.1]

All REST operations supports also the new Task-based Asynchronous Pattern (TAP) for asynchronous calls.
This is based on the new Task Parallel Library (TPL) provided with .NET 4 and Silverlight 5.
These asynchronous methods are suffixed by the word 'Async' based on common .NET naming conventions, and each returns a Task<T>.
An example is shown below :

// Using a continuation
template.GetForObjectAsync<string>("http://example.com/hotels/bookings")
  .ContinueWith(task =>
  {
    string result = task.Result;
  });
  
// Blocking the current thread
string result = template.GetForObjectAsync<string>("http://example.com/hotels/bookings").Result;
[Warning]Warning

Do not forget to synchronize with the UI thread to interact with the user interface in a continuation as shown below :

// Using a continuation
template.GetForObjectAsync<string>("http://example.com/hotels/bookings")
  .ContinueWith(task =>
  {
    MyTextBox.Text = task.Result;
  }, TaskScheduler.FromCurrentSynchronizationContext());  // execute on UI thread
[Note]Note

Using the new TPL is the recommended way to perform asynchronous operations in .NET 4.0 and later.

2.2. Configuring the RestTemplate

2.2.1. Base address

In some cases it may be useful to set up the base url of the request once. This is possible by setting the base address in the constructor or by setting the property BaseAddress.
For example:

RestTemplate template = new RestTemplate("http://example.com");
Booking booking1 = template.GetForObject<Booking>("/hotels/{id}/bookings", 1);
Booking booking2 = template.GetForObject<Booking>("/hotels/{id}/bookings", 2);

2.2.2. HTTP message converters

Objects passed to and returned from REST operations are converted to and from HTTP messages by IHttpMessageConverter instances.

Converters for the main mime types are registered by default, but you can also write your own converter and register it via the MessageConverters property.

The default converter instances registered with the template, depending of the target Framework, are ByteArrayHttpMessageConverter, StringHttpMessageConverter, FormHttpMessageConverter, XmlDocumentHttpMessageConverter, XElementHttpMessageConverter, Atom10FeedHttpMessageConverter and Rss20FeedHttpMessageConverter.

You can override these defaults using the MessageConverters property. This is required if you want to use the XmlSerializableHttpMessageConverter/DataContractHttpMessageConverter or DataContractJsonHttpMessageConverter/NJsonHttpMessageConverter.

For example :

// Add a new converter to the default list
RestTemplate template = new RestTemplate("http://twitter.com");
template.MessageConverters.Add(new DataContractJsonHttpMessageConverter());


See HTTP message conversion chapter for detailed description of each converter.

2.2.3. Error handling

In case of an exception processing the HTTP method, an exception of the type RestClientException will be thrown. The interface IResponseErrorHandler allows you to determine whether a particular response has an error and to handle it. The default implementation DefaultResponseErrorHandler throws an exception when a HTTP client or server error happens (HTTP status code 4xx or 5xx).

The default behavior can be changed by plugging in another implementation into the RestTemplate via the ErrorHandler property. The example below shows a custom IResponseErrorHandler implementation that inherits from existing DefaultResponseErrorHandler and which throws an exception only when a HTTP server error happens (HTTP status code 5xx).

public class MyResponseErrorHandler : DefaultResponseErrorHandler
{
  protected override bool HasError(HttpStatusCode statusCode)
  {
    int type = (int)statusCode / 100;
    return type == 5;
  }
}

RestTemplate template = new RestTemplate("http://example.com");
template.ErrorHandler = new MyResponseErrorHandler();

HttpResponseMessage responseMessage = template.PostForMessage("/notfound", null); // throw HttpClientErrorException with default implementation
if (responseMessage.StatusCode == HttpStatusCode.NotFound)
{
  // ...
}

[Note]Note

ErrorHandler property may be set to null to give the user total control over the response.

2.2.4. Request factory

RestTemplate uses a request factory to create instances of the IClientHttpRequest interface. Default implementation uses the .NET Framework class HttpWebRequest. This can be overridden by specifying an implementation of IClientHttpRequestFactory via the RequestFactory property.

The default implementation WebClientHttpRequestFactory uses an instance of HttpWebRequest which can be configured with credentials information or proxy settings. An example setting the proxy is shown below :

WebClientHttpRequestFactory requestFactory = new WebClientHttpRequestFactory();
requestFactory.Proxy = new WebProxy("http://proxy.example.com:8080");
requestFactory.Proxy.Credentials = new NetworkCredential("userName", "password", "domain");

RestTemplate template = new RestTemplate("http://example.com");
template.RequestFactory = requestFactory;

2.2.4.1. Silverlight support

In Silverlight, HTTP handling can be performed by the browser or the client. See How to: Specify Browser or Client HTTP Handling on MSDN.
By default, WebClientHttpRequestFactory will use the browser HTTP stack for HTTP methods GET and POST, and force the client HTTP stack for other HTTP methods.
This can be overridden by setting the WebRequestCreator property.

RestTemplate template = new RestTemplate("http://example.com");
((WebClientHttpRequestFactory)rt.RequestFactory).WebRequestCreator = WebRequestCreatorType.ClientHttp;

2.2.5. Request interceptors

RestTemplate allows you to intercept HTTP request creation and/or execution. You can create your own interceptor and register it via the RequestInterceptors property.

Four types of interceptors are provided :

  • IClientHttpRequestFactoryInterceptor will intercept request creation, allowing to modify the HTTP URI and method, and to customize the newly created request.

  • IClientHttpRequestBeforeInterceptor will intercept request before its execution, allowing to modify the HTTP headers and body. This interceptor supports both synchronous and asynchronous requests.

  • IClientHttpRequestSyncInterceptor will intercept synchronous request execution, giving total control of the execution (error management, logging, perf, etc.).

  • IClientHttpRequestAsyncInterceptor will intercept asynchronous request execution, giving total control of the execution (error management, logging, perf, etc.).

An example of an interceptor measuring HTTP request execution time is shown below.

public class PerfRequestSyncInterceptor : IClientHttpRequestSyncInterceptor
{
  public IClientHttpResponse Execute(IClientHttpRequestSyncExecution execution)
  {
    Stopwatch stopwatch = Stopwatch.StartNew();   
    IClientHttpResponse response = execution.Execute();
    stopwatch.Stop();
    
    Console.WriteLine(String.Format(
      "Sync {0} request for '{1}' took {2}ms and resulted in {3:d} - {3}",
      execution.Method,
      execution.Uri,
      stopwatch.ElapsedMilliseconds, 
      response.StatusCode));
    
    return response;  
  }
}

RestTemplate template = new RestTemplate();
template.RequestInterceptors.Add(new PerfRequestSyncInterceptor());

Note that you can also make PerfRequestSyncInterceptor implement IClientHttpRequestAsyncInterceptor to support both synchronous and asynchronous requests.

2.2.6. Using the Spring.NET container

Spring.NET REST Client Framework has no direct dependency on the Spring.NET Framework. It can be used either by itself in isolation or in combination with the remainder of the Spring.NET Framework to suit different usage scenarios.

RestTemplate, as with any other object, can be configured in the Spring.NET container.
For example, using XML configuration :

<object id="RestTemplate" type="Spring.Rest.Client.RestTemplate, Spring.Rest">
  <constructor-arg name="baseAddress" value="http://example.com"/>
  <property name="ErrorHandler">
    <object type="MyErrorHandler"/>
  </property>
  <property name="MessageConverters">
    <list>
      <object type="MyHttpMessageConverter"/>
    </list>
  </property>
  <property name="RequestInterceptors">
    <list>
      <object type="MyClientHttpRequestInterceptor"/>
    </list>
  </property>
  <property name="RequestFactory.UseDefaultCredentials" value="true"/>
  <property name="RequestFactory.Timeout" value="10000"/>
</object>

Or using Code-based configuration :

[Configuration]
public class MyAppConfiguration
{
  [Definition]
  public virtual IRestOperations MyRestClient()
  {
    return new RestTemplate("http://localhost/MyService/");
  }
}

2.3. Authenticating requests

2.3.1. Using HttpWebRequest .NET class

The default request factory implementation WebClientHttpRequestFactory, that uses the HttpWebRequest class, can be used to authenticate the HTTP request. Supported authentication schemes include Basic, Digest, Negotiate (SPNEGO), Kerberos, NTLM, and Certificates.

WebClientHttpRequestFactory requestFactory = new WebClientHttpRequestFactory();
requestFactory.Credentials = new NetworkCredential("userName", "password", "domain");

RestTemplate template = new RestTemplate("http://example.com");
template.RequestFactory = requestFactory;

You can also directly cast the default request factory to WebClientHttpRequestFactory :

RestTemplate template = new RestTemplate("http://example.com");
((WebClientHttpRequestFactory)template.RequestFactory).UseDefaultCredentials = true;

2.3.2. Basic authentication

Basic authentication is supported by the WebClientHttpRequestFactory (see previous section), but this implementation will wait the challenge response from server before to send the 'Authorization' header value. As this can be an issue in some cases, Spring provides a custom request interceptor named BasicSigningRequestInterceptor that forces Basic authentication. This is shown below

RestTemplate template = new RestTemplate("http://example.com");
template.RequestInterceptors.Add(new BasicSigningRequestInterceptor("login", "password"));

2.3.3. OAuth

This is supported by the Spring.NET Social project.
The implementation is based on request interceptors.

2.4. Dealing with HTTP messages

Besides the REST operations described in the previous section, the RestTemplate also has the Exchange() method, which can be used for arbitrary HTTP method execution based on HTTP messages. The method takes as arguments the HTTP request message composed of the request Uri, the HTTP method and the HTTP entity (headers and body) and returns the HTTP response message composed of the status code, status description and the HTTP entity (headers and body).

HttpResponseMessage<T> Exchange<T>(Uri url, HttpMethod method, HttpEntity requestEntity) where T : class;

// also has 2 overloads for URI template based URL.

Perhaps most importantly, the Exchange() method can be used to add request headers and read response headers for every REST operation. For example:

HttpEntity requestEntity = new HttpEntity();
requestEntity.Headers["MyRequestHeader"] = "MyValue";

HttpResponseMessage<string> response = template.Exchange<string>("/hotels/{hotel}", HttpMethod.GET, requestEntity, 42);

string responseHeader = response.Headers["MyResponseHeader"];
string body = response.Body;
HttpStatusCode statusCode = response.StatusCode;
string statusDescription = response.StatusDescription;

In the above example, we first prepare a request message that contains the MyRequestHeader header. We then retrieve the response message, and read the MyResponseHeader.

2.5. Under the hood...

Last but not least, the Execute() method is behind everything RestTemplate does.

T Execute<T>(Uri url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor) where T : class;

// also has 2 overloads for URI template based URL.

The IRequestCallback interface is defined as

public interface IRequestCallback
{
  void DoWithRequest(IClientHttpRequest request);
}

The IResponseExtractor<T> interface is defined as

public interface IResponseExtractor<T> where T : class
{
  T ExtractData(IClientHttpResponse response);
}

The Execute method allow you to manipulate the request/response headers, write to the request body and read from the response body.

Note, when using the execute method you do not have to worry about any resource management, the template will always close the request and handle any errors. Refer to the API documentation for more information on using the execute method and the meaning of its other method arguments.

2.6. Testing RestTemplate based code

[Since 1.1]

Spring.NET REST Client also includes a framework for unit testing RestTemplate based code (Spring.Rest.Testing.dll)

This framework consists of a MockRestServiceServer class that can be used to mock out REST calls to the remote service provider.
This allows for the development of independent, performant, automated unit tests that verify client REST binding and object mapping behavior.

The typical usage of this class is:

  • Create a MockRestServiceServer instance by calling MockRestServiceServer.CreateServer(RestTemplate) method with the RestTemplate to test.

  • Set up request expectation by calling MockRestServiceServer.ExpectNewRequest() method.
    More request expectations can be set up by chaining IRequestActions.AndExpect(RequestMatcher) calls, possibly by using the default method extensions provided.

  • Create an appropriate response message by calling IRequestActions.AndRespond(ResponseCreator) method, possibly by using the default method extensions provided.

  • Call MockRestServiceServer.Verify() method.

You can find an example of the testing framework in the examples directory (Spring.TestingQuickStart solution).

[Note]Note

For complete testing examples, consult the unit tests source code of the Spring.NET Social project and its extensions.