Acceder a servicios Rest con .NET

¡Hola!
Hoy voy a enseñaros un pequeño proyecto con el que poder acceder a servicios REST sencillos. La ventaja es que sólo tendremos que crear la entidad de la consulta (request) y de la respuesta (response).
Vamos a ver un ejemplo de cómo hacer la entidad para una consulta al API de geocodificación de Google Maps. Queremos que, dada una dirección postal, nos devuelva las coordenadas (latitud, longitud).

Vamos a echar un vistazo a una consulta básica: https://maps.googleapis.com/maps/api/geocode/xml?parametros (más info en aquí).
Nuestra entidad de consulta sería:

public class Attributes : Attribute
{
   public string PropertyName { get; set; }
   public Attributes() { }
   public Attributes(string propertyName) { this.PropertyName = propertyName; }
}
 
public class GeocodeRequest
{
   [Attributes(PropertyName = "address")]
   public string Address { get; set; }
   [Attributes(PropertyName = "region")]
   public string Region { get; set; }
   [Attributes(PropertyName = "sensor")]
   public string Sensor { get; set; }
   [Attributes(PropertyName = "language")]
   public string Language { get; set; }
}

Ahora vamos a ver la respuesta XML de una consulta:

<?xml version="1.0" encoding="UTF-8" ?>
<GeocodeResponse>
<status>OK</status>
<result>
<type>locality</type>
<type>political</type>
<formatted_address>Valladolid, Valladolid, España</formatted_address>
<address_component>
<long_name>Valladolid</long_name>
<short_name>Valladolid</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Valladolid</long_name>
<short_name>Valladolid</short_name>
<type>administrative_area_level_4</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Valladolid</long_name>
<short_name>VA</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Castilla y León</long_name>
<short_name>CL</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>España</long_name>
<short_name>ES</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>41.6522510</lat>
<lng>-4.7245321</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>41.5909983</lat>
<lng>-4.7754894</lng>
</southwest>
<northeast>
<lat>41.6780956</lat>
<lng>-4.6894439</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>41.5909983</lat>
<lng>-4.9281803</lng>
</southwest>
<northeast>
<lat>41.8155086</lat>
<lng>-4.6894439</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJk27GCIxyRw0R72uiHNSS_7M</place_id>
</result>
</GeocodeResponse>

El siguiente paso es crear nuestra entidad para la respuesta:

[XmlRoot("result")]
public class Geocode
{
   [XmlElement("geometry")]
   public Geometry Geometry { get; set; }
}
 
[XmlRoot("GeocodeResponse")]
public class GeocodeResponse
{
   [XmlElement("status")]
   public string Status { get; set; }
   [XmlElement("result")]
   public Geocode Geocode { get; set; }
}
 
[XmlRoot("geometry")]
public class Geometry
{
   [XmlElement("location")]
   public Location Location { get; set; }
}
 
[XmlRoot("location")]
public class Location
{
   [XmlElement("lat")]
   public float Latitude { get; set; }
   [XmlElement("lng")]
   public float Longitude { get; set; }
}

¿Y qué es lo que estamos haciendo?
Por partes.

  • En la entidad de la consulta (GeocodeRequest), definimos las propiedades y en su atributo PropertyName, el valor real que tendrá en la solicitud
  • En la entidad de la respuesta, definimos el modelo que corresponde al archivo XML que nos devuelve el servicio de geocodificación, indicando el XmlElement al que corresponde cada propiedad de la entidad con respecto a su homólogo en el archivo XML.

Y ya está… o casi.

El último paso es utilizar los servicios correspondientes para obtener las coordenadas a partir de nuestro modelo de consulta y respuesta:

static async Task MainAsync()
{
   Console.WriteLine("Introduce una dirección");
   var city = Console.ReadLine();
   var location = await GetCoordinates(city);
   Console.WriteLine("Las coordenadas de {0} son {1},{2}", city, location.Latitude, location.Longitude);
}
 
private static async Task<Location> GetCoordinates(string address)
{
   ICreateRequestService<GeocodeRequest> requestService = new CreateBasicRequestService<GeocodeRequest>();
   requestService.BaseRequest = @"http://maps.googleapis.com/maps/api/geocode/xml?";
   //requestService.Equal = "=";
   //requestService.Separator = "&";
   IClientService clientService = new ClientRequestService();
   ISerializeService<GeocodeResponse> serializeService = new SerializeXmlService<GeocodeResponse>();
 
   IRestService<GeocodeRequest, GeocodeResponse> restService = new RestService<GeocodeRequest, GeocodeResponse>(
requestService, clientService, serializeService);
 
   GeocodeRequest request = new GeocodeRequest()
   {
      Address = address,
      Language = "es",
      Region = "es",
      Sensor = "false"
   };
   var response = await restService.Get(request);
   return response.Geocode.Geometry.Location;
}

Y… voilà. Ya tenemos nuestro resultado:

La parte de añadir las dependencias a IRestService, la podríamos hacer con Ninject, Unity, Autofac…

Podéis ver el proyecto completo en Github. Hay un ejemplo muy parecido al que hemos hecho.

PD: También se puede hacer con peticiones JSON. La diferencia única diferencia que en vez de utilizar SerializeXmlService, usaríamos SerializeJsonService, y en vez de utilizar en la entidad de la respuesta la propiedad XmlElement, la cambiaríamos por JsonProperty. Hay por ahí test donde se puede ver un ejemplo.

¡Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *