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.

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 another class called WebClient but does not support HTTP headers and HTTP status code/description.

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 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 are also available for asynchronous calls. The asynchronous methods are suffixed by the word 'Async' based on common .NET naming conventions.


Note, that asynchronous call were initially added to support Silverlight and Windows Phone, but nothing prevents you from using them for Windows Forms and WPF applications to not freeze 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.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 JsonHttpMessageConverter/NJsonHttpMessageConverter.

For example :

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


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. The default implementation 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 which gives the user total control over the response.

public class MyResponseErrorHandler : IResponseErrorHandler
{
  public bool HasError(IClientHttpResponse response)
  {
    return false;
  }

  public void HandleError(IClientHttpResponse response)
  {
    // This method should not be called because HasError returns false.
    throw new InvalidOperationException();
  }
}

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)
{
  // ...
}

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

RestTemplate, as any other class 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>

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 will be supported in a future version based on the Spring.Social Java 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.