REST define un estilo de arquitectura centrada en recursos. Estos recursos son accedidos mediante el uso de URI’s y verbos HTTP (GET, POST, PUT y DELETE) en vez de basarnos en el SOAPAction como lo hace SOAP.
Algunos de los beneficios de REST son:
- Ligereza. No se incluye xml extra como ocurre en los paquetes SOAP.
- El resultado devuelto por REST es fácilmente entendible. Como se suele decir es Human Readable.
- No se necesitan toolkits para su uso.
- Simple. Tiene menos funcionalidad evidentemente que un servicio basado en soap/WS-*, pero en muchos casos nos debería sobrar con esa funcionalidad.
Si quisiéramos invocar a un web service que nos devolviera un cliente con identificador 25 y este web service fuera RESTful, la URI necesaria para invocar a ese recurso sería la siguiente:
http://demo/ventas.svc/cliente/25
En cambio en el caso de un web service basado en SOAP, mediante la URI solamente podríamos identificar el endpoint del servicio:
http://demo/ventas.svc
y como mucho la operación a invocar:
http://demo.ventas.asmx?op=ObtenerClientes
Una vez que ya “sabemos” en que consiste REST, vamos a implementar un servicio RESTFul basándonos en WCF.
Creación del Servicio
- Lo primero de todo va a ser crear un nuevo servicio, para ello vamos a basarnos en la plantilla por defecto de VS 2008. Llama al proyecto RESTService.
2. Renombrar el archivo IService1 por ICalculadora y modifica el contenido de éste con el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
namespace RESTService
{
[ServiceContract]
public interface ICalculadora
{ [OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate="/Sumar/{op1}/{op2}")] string Sumar(string op1,string op2);
}
}
La única diferencia con un Servicio WCF es que hemos añadido el atributo WebGet al método Sumar. Este atributo indica que la operación es de recuperación y que puede ser llamada mediante el modelo de programación web. Además estamos indicando que la URI para acceder al recurso es del estilo http://servidor/RESTService.Calculadora.svc/Sumar/25/50.
Nota: Veréis que los parámetros en este caso son string aunque deberían ser numéricos. Esto es porque UriTemplate nos lo exige así.
En el caso de que la operación no sea de recuperación, sino de modificación el atributo que deberemos usar es [WebInvoke].
Ejemplo:
1: [OperationContract]
2: [WebInvoke(Method="DELETE",UriTemplate="/Producto/{idProducto}")] 3: public void EliminarProducto(string idProducto)
4: { 5: // eliminar el producto cuyo identificador se pasa como parámetro
6: }
3. Renombra el archivo Service1.cs por Calculadora.cs y modifica el contenido de éste con el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace RESTService
{ public class Calculadora : ICalculadora
{ public string Sumar(string op1, string op2)
{ int operando1=0;
int operando2=0;
string sResultado = "";
if ((int.TryParse(op1, out operando1)) && (int.TryParse(op2, out operando2)))
{ sResultado= string.Format("El resultado de la suma es: {0}", operando1 + operando2); }
return sResultado;
}
}
}
Como se puede apreciar, el código implementa un método sumar que toma como entrada dos parámetros y devuelve como resultado la suma de estos. Aquí no hay diferencia entre un Servicio “normal” y uno RESTful.
4. Verifica que en el archivo app.config se han reflejado todos los cambios de nombres que hemos hecho a los archivos de código.
5. Localiza la definición del endpoint y modifica el binding wsHttpbinding por webHttpbinding. Al final debes tener algo parecido a lo siguiente:
<endpoint address="" binding="webHttpBinding"
contract="RESTService.ICalculadora" behaviorConfiguration="WebBehavior">
6. Añade dentro del nodo <behaviors> el siguiente xml:
<endpointBehaviors>
<behavior name="WebBehavior">
<webHtpp/>
</behavior>
</endpointBehaviors>
El binding webHttpbinding indica que este servicio debe ser expuesto a través de peticiones HTTP que expongan Plain old XML (POX) en vez de mensajes basados en SOAP. Este binding se usa en conjunción con el behavior WebHttp para habilitar el modelo de programación web para un servicio WCF.
Con esto ya hemos creado un servicio RESTFul.
Consumo del Servicio
Un servicio RESTful se puede invocar de dos maneras:
- Invocando directamente al servicio a través del objeto WebChannelFactory.
- Añadiendo una referencia al servicio y modificando mínimamente el proxy.
A mi la que mas me gusta es la segunda, ya que queda todo mucho mas limpio y además seguimos invocando a todos los servicios de la misma forma con independencia de la forma en que estos se expongan.
Método 1 (WebChannelFactory)
1. Crea un proyecto de consola que utilizaremos para probar el Servicio RESTFul.
2. Añade una referencia al namespace System.ServiceModel.Web.
3. Añade una copia del archivo ICalculadora.cs a este proyecto.
4. Añade el siguiente código para consumir el servicio:
1: WebChannelFactory<ICalculadora> factory = new WebChannelFactory<ICalculadora>(new Uri("ruta de tu servicio")); 2: ICalculadora proxy = factory.CreateChannel();
3: string response = proxy.Sumar("25","70"); 4: ((IDisposable)proxy).Dispose();
Acuérdate de modificar “ruta de tu servicio” por la URL donde esté tu servicio RESTFul.
Este método de invocación no necesita una referencia al servicio, solo es necesario poder acceder al Interface del servicio.
Método 2 (Add Services Reference)
1. Crea un proyecto de consola que utilizaremos para probar el Servicio RESTFul.
2. Añade una referencia al namespace System.ServiceModel.Web.
3. Añade una referencia al servicio RESTFul que quieres consumir.
4. Abre el archivo Reference.cs que contiene el código proxy de invocación al servicio. Localiza el método Sumar y añade el siguiente atributo encima:
1: [WebGet(
2: BodyStyle = WebMessageBodyStyle.Bare,
3: ResponseFormat = WebMessageFormat.Xml,
4: UriTemplate = "/Sumar/{op1}/{op2}")]
Con este atributo le decimos al proxy como debe invocar al servicio.
5. Abre el archivo app.config y localiza el nodo <client> donde añadiremos la definición del endpoint del servicio a consumir:
1: <endpoint address="ruta de tu servicio" behaviorConfiguration="test"
2: binding="webHttpBinding" contract="ServiceReference1.ICalculadora"
3: name="WebHttpBinding1"/>
6.Inmediatamente después del cierre del elemento </client> añade el siguiente xml:
1: <behaviors>
2: <endpointBehaviors>
3: <behavior name="test">
4: <webHttp/>
5: </behavior>
6: </endpointBehaviors>
7: </behaviors>
Una vez hechas estas modificaciones ya podemos invocar al servicio como siempre:
1: CalculadoraClient calc = new ConsoleApplication2.ServiceReference1.CalculadoraClient("WebHttpBinding1"); 2: string response = calc.Sumar("25","70");
Finalmente vamos a usar fiddler para ver las trazas del intercambio de llamadas HTTP entre el cliente y el servicio.
En el caso de la llamada al servicio REST vamos a obtener la siguiente traza:
1: GET /RESTService.Calculadora.svc/Sumar/25/70 HTTP/1.1
2: Content-Type: application/xml; charset=utf-8
3: VsDebuggerCausalityData: uIDPo8iVuDxtWzVIoOWhMWz8d6cAAAAAQQ14Z3Np/kGe9oMjdzTKnIAB0WdKCntFi092ERAO19oACQAA
4: Host: xxxxxx
5: Connection: Keep-Alive
En el caso de la llamada a un servicio SOAP vamos a obtener la siguiente traza:
1: POST /WcfServiceLibrary1.Service1.svc HTTP/1.1
2: Content-Type: text/xml; charset=utf-8
3: VsDebuggerCausalityData: uIDPo9JShnIh9h9LnpM3i3SLcV8AAAAADD0BBgGqLkCAeQs6rXWB4Cv3lHKbfRpOq02eDFtYkC4ACQAA
4: SOAPAction: "http://tempuri.org/IService1/GetData"
5: Host: xxxxxxxx
6: Content-Length: 158
7: Expect: 100-continue
8: Connection: Keep-Alive
9:
10: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
11: <s:Body>
12: <GetData xmlns="http://tempuri.org/">
13: <value>25</value>
14: </GetData>
15: </s:Body>
16: </s:Envelope>
Si comparamos una traza con otra, veremos que en el servicio “REST” es la operación GET la que define el método a invocar y los parámetros que queremos pasarle, no existe el SOAPAction, mientras que en el servicio “SOAP” necesitamos un SOAPAction donde definamos el método a invocar a parte de un envelope donde definimos los parámetros que le pasamos a este método.
La respuesta del servicio “REST” será la siguiente:
1: HTTP/1.1 200 OK
2: Content-Type: application/xml; charset=utf-8
3: Server: Microsoft-IIS/7.0
4: X-Powered-By: ASP.NET
5: Date: Mon, 27 Apr 2009 14:33:52 GMT
6: Content-Length: 92
7:
8: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">El resultado de la suma es: 95</string>
La respuesta del servicio “SOAP” será la siguiente:
1: HTTP/1.1 200 OK
2: Content-Type: text/xml; charset=utf-8
3: Server: Microsoft-IIS/7.0
4: X-Powered-By: ASP.NET
5: Date: Mon, 27 Apr 2009 14:28:00 GMT
6: Content-Length: 203
7:
8:
9:
10: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
11: <s:Body>
12: <GetDataResponse xmlns="http://tempuri.org/">
13: <GetDataResult>You entered: 25</GetDataResult>
14: </GetDataResponse>
15: </s:Body>
16: </s:Envelope>
Como vemos en las trazas, la respuesta de un servicio “REST” es mucho mas simple y de menor tamaño que la respuesta de un servicio “SOAP”.
En en el siguiente enlace RESTService.zip tienes los archivos del ejemplo disponibles. Es un ejemplo muy simple pero que explica las bases para la creación de un servicio REST.
Por último solamente queda decir que Microsoft ha publicado en codeplex un Starter Kit (Preview 2) que proporciona clases y plantillas para la creación de servicios RESTFul.
En otro post veremos como crear y consumir un servicio usando este Starter kit.
Saludos.