Sono sempre stato un appassionato di soluzioni REST-ful e la nuova versione di Spring.NET REST Client costituisce a mio avviso un ottimo strumento per implementare il client di un qualunque servizio REST in maniera molto semplice e potente, non solo su framework 2.0/3.5/4.0, ma anche su Silverlight 3 e 4, Compact Framework 2.0/3.5 e Windows Phone 7.
Queste API client fanno capo ad una classe di riferimento chiamata RestTemplate. Si tratta a tutti gli effetti di un helper che astrae in maniera molto semplice ognuno dei sei principali metodi HTTP che possono essere supportati da un servizio REST (GET, POST, HEAD, OPTIONS, PUT, DELETE). I metodi di questa classe infatti seguono una “naming convention” in cui la prima parte del metodo indica il verbo HTTP della richiesta e la seconda parte esplicita la rappresentazione della risposta, la quale può essere ad esempio un oggetto deserializzato o l'Uri di una risorsa.
Ecco un esempio:
var newCustomer = new Customer { FirstName = "Dario", LastName = "Santarelli" };
RestTemplate restTemplate = new RestTemplate("http://localhost");
// POST (Creates) the Customer resource
Uri newCustomerUri = restTemplate.PostForLocation("/myRestService/Customers", newCustomer);
// GET the Customer resource
Customer customerObj = restTemplate.GetForObject<Customer>(newCustomerUri);
HttpResponseMessage<Customer> customerMsg = restTemplate.GetForMessage<Customer>(newCustomerUri);
string customerBodyString = restTemplate.GetForObject<string>(newCustomerUri);
byte[] customerBodyBytes = restTemplate.GetForObject<byte[]>(newCustomerUri);
// DELETE the Customer resource
restTemplate.Delete(newCustomerUri);
Anzitutto si chiede al servizio REST di creare una risorsa Customer tramite il metodo PostForLocation(), il quale restituisce la Uri della risorsa appena creata, che possiamo quindi accedere con una GET in varie forme: tramite il metodo GetForObject<T>() potremmo cercare di deserializzare la risposta HTTP direttamente in un oggetto Customer oppure potremmo ottenerne la rappresentazione raw (es. XML, JSON etc.) specificando il tipo T come string. Infine, cancelliamo la risorsa tramite una DELETE. Da notare come GetForObject<T>() e GetForMessage<T>() dietro le quinte eseguano entrambi due GET HTTP ma ritornano nel primo caso un oggetto mentre nel secondo caso un message-wrapper di tipo HttpResponseMessage che espone informazioni aggiuntive come StatusCode e Header. Per questi metodi esistono anche degli overload con il suffisso “Async” per gestire appunto pattern di invocazione asincrona (indispensabili su Silverlight e Windows Phone).
Per completezza, c’è da dire che per effettuare le chiamate REST si può utilizzare anche un metodo alternativo Exchange() che permette di interagire direttamente con i verbi HTTP ed oggetti di tipo HttpEntity (da specifica HTTP 1.1, section 7) eventualmente per impostare degli header custom nella richiesta. Ad esempio...
HttpEntity requestEntity = new HttpEntity();
requestEntity.Headers["headerKey"] = "headerValue";
HttpResponseMessage<Customer> response = restTemplate.Exchange<Customer>("/myRestService/Customers/{id}",
HttpMethod.GET, requestEntity, 1);
string responseHeader = response.Headers["responseHeaderKey"];
Customer customer = response.Body;
HttpStatusCode statusCode = response.StatusCode;
string statusDescription = response.StatusDescription;
Per deserializzare correttamente il tipo T specificato ad esempio nei metodi GetForObject<T>() e GetForMessage<T>(), il RestTemplate usa internamente una classe chiamata MessageConverterResponseExtractor<T> che è in grado di convertire una risposta HTTP in un'istanza di tipo T tramite dei MessageConverters. A mio avviso la vera potenza di RestTemplate sta proprio in questa parte, ovvero nel fatto che può essere facilmente configurato per supportare diversi MessageConverters, delle classi il cui ruolo è convertire oggetti in messaggi HTTP e viceversa in base al media type. Le strategie di conversione sono veramente tante e possono sfruttare sia serializer “standard” del framework come XmlSerializer, DataContractSerialier, DataContractJsonSerializer piuttosto che altre strategie di conversione custom (es. basate su SyndacationFeed e SyndicationItem per feed ATOM e RSS piuttosto che su Json.NET per accedere ai valori JSON in modo diretto etc.). Ad esempio, possiamo fare in modo che i messaggi HTTP con media type application/json vengano gestiti dal DataContractJsonSerializer del framework semplicemente scrivendo…
RestTemplate restTemplate = new RestTemplate("http://localhost");
restTemplate.MessageConverters.Add(new JsonHttpMessageConverter());
N.B.: i MessageConverters caricati per default cambiano in base al target framework di compilazione. Tuttavia, tutti i converter devono implementare l’interfaccia IHttpMessageConverters, quindi possiamo facilmente implementarcene uno custom e renderlo operativo in modo molto semplice ed intuitivo.
Oltre ai MessageConverters , Spring.NET REST Client supporta anche altre features molto interessanti:
- RestTemplate espone una proprietà RequestFactory che offre la possibilità di personalizzare il meccanismo di generazione delle richieste HTTP. Per default questa proprietà viene valorizzata con un’ istanza della classe WebClientHttpRequestFactory, che a sua volta internamente usa la classe HttpWebRequest del framework. Ciò offre gratuitamente la possibilità di supportare proxy HTTP ad esempio.
- Altra proprietà interessante di RestTemplate è RequestInterceptors, ovvero una collezione di interceptors che ci permette di inserirci sia in modo sincorno che in modo asincrono in un qualunque punto della pipeline di crezione ed esecuzione della richiesta HTTP, magari per modificare la richiesta al volo piuttosto che per iniettare gestioni custom di error management, logging, etc.
Technorati tags:
Spring.NET,
REST