Api Management: Convertir XML a JSON usando políticas ¡sin modificar las Apis!

En el mes de Octubre hice una breve introducción a Api Management, uno de los nuevos servicios de la plataforma Microsoft Azure. La función principal de este es centralizar el uso de nuestras Apis por terceros, aunque lo cierto es que nos va permitir mucho más: establecer cuotas, reescribir URLs, modificar el contenido de la respuesta, conversión entre formatos, etcétera. Muchos de estos poderes extra se consiguen a través de lo que se conocen como políticas. En este post voy a mostraros cómo de fácil es transformar el resultado de una Api, que sólo devuelve XML, a JSON.

La Api

En primer lugar he creado servicio con Windows Communication Foundation, el cual tiene el siguiente aspecto:

using System.ServiceModel;
using System.ServiceModel.Web;
using WcfService.Model;

namespace WcfService
{

    [ServiceContract(Namespace = "")]
    public interface IService
    {

        [OperationContract]
        [WebGet]
        Profile GetData(int id, string name, string address);

    }
}

Esta demo sólo expone un método llamado GetData, el cual recibe todos los valores necesarios para construir y devolver un objeto del tipo Profile tal y como se muestra en su implementación:

using WcfService.Model;

namespace WcfService
{
    public class Service : IService
    {
        public Profile GetData(int id, string name, string address)
        {
            return new Profile { Id = id, Name = name, Address = address };
        }
    }
}

Respecto a la configuración del servicio con WCF, se ha creado un binding del tipo webHttpBinding, se ha expuesto utilizando un behaviour webHttp y se ha dejado el resto de la configuración por defecto.

  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="webBinding"></binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="WcfService.Service" behaviorConfiguration="MyBehavior">
        <endpoint address="xml"
                  binding="webHttpBinding"
                  bindingConfiguration="webBinding"
                  behaviorConfiguration="xmlBehavior"
                  contract="WcfService.IService"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="xmlBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyBehavior">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
Si quieres saber más sobre cómo crear un servicio con WCF quizás te interese este post.

Antes de añadir el servicio a Api Management, podemos comprobar el resultado que genera utilizando Fiddler:

Fiddler testing WCF service

Policies

En el apartado Policies elegimos el método GetData a través de los combos y seleccionamos la opción ADD POLICY en el cuadro inferior.

Policies combo and add policy

A partir de este momento el cuadro de configuración de políticas estará activado, mostrando la siguiente información:

<!--
    IMPORTANT:
        - Policy statements MUST be enclosed within either <inbound> or <outbound> elements.
        - <base /> elements represent policy-in-effect inherited from the outer scopes.
        - <inbound> element contains policies to be applied in the inbound direction (from caller to web service).
        - <outbound> element contains policies to be applied in the outbound direction (from web service to caller).
        - Policies are applied in the order they appear.

    To ADD a policy, position cursor in the policy document to specify the insertion point and click on the associated button for a desired policy statement button.
    To REMOVE a policy, delete the corresponding policy statement from the policy document.
    To RE-ORDER a policy, select the corresponding policy statement and cut-and-paste it into a new location within the policy document.
-->
<policies>
    <inbound>

        <base />

    </inbound>
    <outbound>

La configuración es muy sencilla: la etiqueta base se utiliza para heredar todas las políticas que estén definidas en niveles superiores. Inbound se utiliza para especificar políticas de entrada y outbound de salida.
En el caso de la conversión de XML a JSON se trata de una política de salida. Para crearla posicionamos el cursor en el apartado outbound y seleccionamos el enlace Convert XML to JSON, ayudándonos de los valores que se muestran al lado derecho del cuadro, policy statements.

Policy Outbound Convert XML to JSON

La línea que se agrega es la siguiente:

<xml-to-json kind="javascript-friendly | direct" apply="always | content-type-xml" consider-accept-header="true | false"/>

Existe un apartado en la documentación de Api Management, llamado Azure API Management Policy Reference, donde podemos ver todos los valores y políticas que están soportadas actualmente. Respecto a este ejemplo, podemos conocer cuáles son los valores que podemos configurar aquí. Esta es la configuración que he elegido:

<xml-to-json kind="javascript-friendly" apply="content-type-xml" consider-accept-header="true"/>

Developer portal

La forma más sencilla de comprobar que la política funciona correctamente es a través del Developer portal, al cual se puede acceder desde el menú superior del portal de administración. Una vez en él, elegimos el servicio desde el apartado APIS y abrimos la consola. Si introducimos 3 valores aleatorios para los parámetros y hacemos clic sobre HTTP GET el resultado debería mostrarse en formato XML.

Api Response content without headers

Para conseguir la conversión a JSON, basta con añadir la cabecera accept: application/json en la petición:

Api get profile accept json example

Si comprobamos el resultado, esta vez habrá sido transformado a JSON:

Api response content with header

¡Saludos!