Mostrando entradas con la etiqueta sequencia. Mostrar todas las entradas
Mostrando entradas con la etiqueta sequencia. Mostrar todas las entradas

sábado, 2 de febrero de 2019

WSO2 Mediator Tutorial: Como evitar incluir namespace con enrich

Ya vimos hace poco la diferencia del enrich y el payload como mediators en WSO2, aquí. Con Payload al sustituir el body teniamos un mayor control de la salida del mismo. Con enrich podemos modificar la respuesta remplazando un valor o añadiendo un hijo/hermano.

Partiendo del ejemplo anterior, podemos indicar que la respuesta recibida en formato XML a través del siguiente código:

<property name="messageType" value="text/xml" scope="axis2"/>

Y será el Enterprise Integrator el encargado de transformalo correctamente gracias a los Message formatter. Y por lo tanto la nueva salida de nuestro método será la siguiente:

<jsonObject>
    <bookstore>
        <name>the starts my destination</name>
        <author>Alfred Bester</author>
    </bookstore>
    <description xmlns="http://ws.apache.org/ns/synapse">list of books</description>
    <bookstore>
        <name>Ender's Game</name>
        <author>Orson S. Card</author>
    </bookstore>
    <total xmlns="http://ws.apache.org/ns/synapse">2</total>
</jsonObject>

Aparte de que al recibir originalmente la respuesta como un json y aunque transforma dicha respuesta a XML la incluye dentro del nodo 'jsonObject'. Podemos ver como aquellos nodos que hemos incluido como hermano o hijo se han creado con un namespace por defecto.

En algunos casos esto puede darnos igual, pero es posible que esta respuesta sea validada por otra entidad a través de un XSD o alguna otra cosa. Y por tanto dichos namespace nos podrian generar fallos.

Para evitar la inclusión del namespace hay una solución específica y es indicarle un namespace vacio, así:

<enrich>
    <source clone="false" type="inline">
        <total xmlns="">2</total>
    </source>
    <target action="child" type="body"/>
</enrich>
<enrich>
    <source clone="false" type="inline">
        <description xmlns="">list of books</description>
    </source>
    <target action="sibling" type="custom" xpath="//bookstore"/>
</enrich>

De la forma anterior, la nueva salida será igual pero sin namespaces asociados a los nodos incluidos:

<jsonObject>
    <bookstore>
        <name>the starts my destination</name>
        <author>Alfred Bester</author>
    </bookstore>
    <description>list of books</description>
    <bookstore>
        <name>Ender's Game</name>
        <author>Orson S. Card</author>
    </bookstore>
    <total>2</total>
</jsonObject>

sábado, 5 de enero de 2019

WSO2: Diferencia entre PayloadFactory y Enrich Mediator


Ultimamente estoy trabajando con WSO2 y me había estado resistendo a crear posts de algo tan específico. Pero creo que poco a poco vamos a hacer ejemplos básicos de esta técnologia de integración. 

Para empezar vamos a realizar un post sobre dos de los mediators más comunes que podemos utilizar dentro de una sequencia del Enterprise Integrator. Como son 'PayloadFactory' y 'Enrich'.  El primero de ellos nos permitirá modificar el cuerpo de la respuesta y crear uno nuevo a nuestra conveniencia. El segundo nos permitirá modificar el cuerpo de la respuesta pero solo añadiendole nuevos valores. 

Para el ejemplo partiremos en ambos casos de una API de prueba. Donde en la sequencia de entrada llamaremos a un wiremock que nos devolverá la respuesta mostrada a continuación. Y será esta respuesta la que va a ser modificada por los dos mediators:

{"bookstore": [
      {"name": "the starts my destination", "author": "Alfred Bester"},
      {"name": "Ender's Game", "author": "Orson Scott Card"}
]}

Con el 'PayloadFactory' mediator, vamos a indicar cual queremos que sea nuestra nueva respuesta. Nos permite incluso crear una nueva respuesta completamente estática, aunque no tenga mucho sentido. Para darle dinamismo tenemos los 'arguments', estos argumentos los indicaremos dentro del cuerpo de la respuesta como '$x', siendo 'x' el ordinal del mismo en la lista global de argumentos. Pueden ser obtenidos de 4 formas: a través de XPath o JSONPath sobre el cuerpo de la actual respuesta, mediante valores literales o con propiedades ya almacenadas en cualquiera de los ambitos dentro del EI. A continuación veremos un ejemplo con JSONPath, literales y valores del contexto:

<payloadFactory media-type="json">
        <format>
{"books":[{"book":[{"name":"$1","author":"$3"}]},{"book":[{"name":"$2","author":"$4"}]}],"total":"$5","description":"$6"}
            </format>
        <args>
            <arg evaluator="json" expression="$.bookstore[0].name" literal="true"/>
            <arg evaluator="json" expression="$.bookstore[1].name" literal="false"/>
            <arg evaluator="json" expression="$.bookstore[0].author" literal="false"/>
            <arg evaluator="json" expression="$.bookstore[1].author" literal="false"/>
            <arg literal="false" value="2"/>
            <arg evaluator="xml" expression="$ctx:description" literal="false"/>
        </args>
    </payloadFactory>

Generando la siguiente salida:

{"books":[
  {"book":[{"name":"the starts my destination","author":"Alfred Bester"}]},
  {"book":[{"name":"Ender's Game","author":"Orson Scott Card"}]}],
  "total":"2","description":"list of books"}

Ahora veremos como funciona el 'Enrich' mediator. Con el basicamente le indicaremos una fuente y un destino, pudiendo realizar 3 tipos de acciones diferentes: añadir como hijo, añadir como hermano o reemplazar. La configuración para la fuente y el destino son similares, se pueden elegir que sean de 4 tipos: personalizada en base a un XPath, envelope del mensaje original, el cuerpo del mensaje original o una propiedad de un ambito. Aunque existe una matrix de compatibilidades para los distintos tipos de fuentes y destinos, por lo que no vale cualquier combinación. Aquí vemos un ejemplo donde añadimos un hijo, un hermano y reemplazamos un valor.

<enrich>
    <source clone="false" type="inline">
        <total>2</total>
    </source>
    <target action="child" type="body"/>
</enrich>
<enrich>
    <source clone="false" type="inline">
        <description>list of books</description>
    </source>
    <target action="sibling" type="custom" xpath="//bookstore"/>
</enrich>
<property name="shortName" scope="default" type="STRING" value="Orson S. Card"/>
<enrich>
    <source clone="false" property="shortName" type="property"/>    <target action="replace" type="custom"
            xmlns:ns="http://org.apache.synapse/xsd" xpath="//bookstore[2]/author"/>
</enrich>

La salida en este caso sería la siguiente:

{"bookstore": { "name": "Ender's Game", "author": "Orson S. Card" }
,"description": "list of books", "total": 2}

Por ulitmo, con enrich una utilidad común es guardar la respuesta original, aunque también lo podemos hacer con el 'Property' mediator. Y luego restablecer dicha respuesta original. Muy util para cuando tienes que hacer llamadas intermedias en tu sequencia.

<property name="REQUEST_PAYLOAD" expression="$body" />
<!-- more code -->
<enrich>
    <source clone="true" xpath="$ctx:REQUEST_PAYLOAD" />    <target type="body" />
 </enrich>