41
www.chakray.com “How to get a Cup of Coffee the WSO2 way” en Español. Juanjo Hernández Documento basado en el artículo de Mr. Hiranya Jayathilaka, titulado “How to GET a Cup of Coffee the WSO2 Way”. El sentido del presente artículo es llevar a la comunidad hispano hablante este recurso, por muchos considerado un buen ejemplo para comprender el manejo de las REST API en WSO2 ESB, así como trasladar el ejemplo a las últimas versiones de WSO2 y exponer los errores y problemas encontrados en su implementación.

Chakray howto get cup of coffee the wso2 way español

  • Upload
    chakray

  • View
    1.095

  • Download
    11

Embed Size (px)

DESCRIPTION

Documento basado en el artículo de Mr. Hiranya Jayathilaka, titulado “How to GET a Cup of Coffee the WSO2 Way”. El sentido del presente artículo es llevar a la comunidad hispano hablante este recurso, por muchos considerado un buen ejemplo para comprender el manejo de las REST API en WSO2 ESB, así como trasladar el ejemplo a las últimas versiones de WSO2 y exponer los errores y problemas encontrados en su implementación

Citation preview

Page 1: Chakray howto get cup of coffee the wso2 way español

w w w . c h a k r a y . c o m

“How to get a Cup of Coffee the

WSO2 way” en Español. Juanjo Hernández Documento basado en el artículo de Mr. Hiranya Jayathilaka, titulado “How to GET a Cup of

Coffee the WSO2 Way”. El sentido del presente artículo es llevar a la comunidad hispano

hablante este recurso, por muchos considerado un buen ejemplo para comprender el

manejo de las REST API en WSO2 ESB, así como trasladar el ejemplo a las últimas

versiones de WSO2 y exponer los errores y problemas encontrados en su implementación.

Page 2: Chakray howto get cup of coffee the wso2 way español

2

Por Juanjo Hernández IT Consultant

Índice

1. Sobre este documento. ............................................................................................ 4

2. Consideraciones tecnológicas. ................................................................................ 5 2.1. Soporte REST en WSO2 middleware. .............................................................. 5 2.2. Soporte API REST en WSO2 ESB. ................................................................... 5 2.3. Mapeos de la URL y plantillas URI. ................................................................... 9 2.4. Configuración de APIs y resources en el ESB. ............................................... 10

3. Diseño de la Solución “Starbucks”. ........................................................................ 11

4. Configuración de los servidores ............................................................................. 14

5. Implementación. ..................................................................................................... 17 5.1. Realizando nuevos pedidos. ........................................................................... 17 5.2. Revisando pedidos. ......................................................................................... 22 5.3. Realizando pagos. ........................................................................................... 23 5.4. Manejando actualizaciones de pedidos. .......................................................... 25 5.5. Recuperando la lista de pedidos pendientes. .................................................. 27 5.6. Revisando el estado del pago. ........................................................................ 29 5.7. Eliminando pedidos completados de la lista. ................................................... 29

6. Mejorando la Solución en general. ........................................................................ 30 6.1. Negociando el formato del contenido (Content Negociation). ......................... 31 6.2. Aplicando Seguridad al API ............................................................................. 32 6.3. Mejorando el rendimiento (Caching). .............................................................. 35

7. Ejecución de la Solución. ....................................................................................... 36 7.1. Clientes GUI. ................................................................................................... 36

8. Problemas encontrados en la implementación original. ........................................ 38

9. Conclusiones. ........................................................................................................ 38

A. Referencias y recursos .......................................................................................... 39

B. Tabla de imágenes ................................................................................................ 39

Autor: ............................................................................................................................ 41

Revisado por: ............................................................................................................... 41

Page 3: Chakray howto get cup of coffee the wso2 way español

3

Por Juanjo Hernández IT Consultant

Page 4: Chakray howto get cup of coffee the wso2 way español

4

Por Juanjo Hernández IT Consultant

1. Sobre este documento.

La curva de aprendizaje en tecnologías ESB suele ser bastante pronunciada. WSO2

dispone de una comunidad no muy grande y en español la información técnica es

bastante escasa.

Muchas son las maneras de introducirse en WSO2 ESB, hay que tener en cuenta que

este ESB se basa y adopta todas las características de proyecto Apache Synapse. Es

este motor ESB y plataforma de intermediación la que es necesaria conocer en

profundidad para llevar a cabo la orquestación de los servicios con WSO2. Por lo que

un vistazo a la página de Documentación de Apache Synapse1 puede ser un buen

comienzo, además de que incorpora un buen número de ejemplos.

En general es más fácil asimilar los conceptos con ejemplos prácticos que permitan

ver a nivel funcional las teorías expresadas mediante arquitecturas TIC. Uno de los

ejemplos más completos e imprescindibles para comprender el uso y las técnicas de

implementación en WSO2 ESB es el ejemplo de Mr. Hiranya Jayathilaka “How to GET

a Cup of Coffee the WSO2 Way2”. Este ejemplo consiste en aplicar la intermediación

del ESB para transformar los mensajes de unos servicios SOAP publicados en un

servidor de aplicaciones a REST que es la manera que las aplicaciones clientes que

consumen los servicios aceptan.

La aplicación se basa en una hipotética implementación de comunicación entre los

clientes de una cafetería de la conocida cadena STARBUCKS con la central de

STARBUCKS que expone, en una capa de servicios SOAP, su OMS3. Los clientes de

dicha cafetería esperan comunicar con el OMS con REST y de aquí el uso de WSO2

ESB para intermediar, transformar, y en un futuro monitorizar y asegurar, dicha

comunicación.

1 http://synapse.apache.org/docs_index.html 2 http://wso2.com/library/articles/2012/09/get-cup-coffee-wso2-way/ 3 Order Management System. http://en.wikipedia.org/wiki/Order_management_system

Page 5: Chakray howto get cup of coffee the wso2 way español

5

Por Juanjo Hernández IT Consultant

Desde Chakray Consulting nos hemos propuesto traducir y mejorar si cabe, el ejemplo

de Mr. Hiranya Jayathilaka y detallar los problemas que nos hemos encontrado en la

implementación práctica del mismo.

2. Consideraciones tecnológicas.

2.1. Soporte REST en WSO2 middleware.

En este ejemplo vamos a usar dos productos que pertenecen a la suite WSO2

middleware, WSO2 ESB4 (WSO2 Enterprise Service Bus) y WSO2 AS5 (WSO2

Application Server)

El Servidor de Aplicaciones de WSO2 (AS), nos hará de servidor OMS y es desde

dónde se encuentra toda la funcionalidad para la gestión de las órdenes que los

clientes REST realizan, dicha funcionalidad se expone en una capa SOAP

El Bus de Servicios Empresarial de WSO2 (ESB), nos servirá para enrutar, filtrar y

transformar las llamadas RESTful. Cualquier proxy service o sequence desplegada en

WSO2 ESB pueden recibir y procesar llamadas REST. El ESB nos va a proporcionar

mecanismos para que la interacción entre clientes RESTful con servicios SOAP y

clientes SOAP con servicios RESTful sea sencilla y cómoda. A partir de la versión

4.0.3, WSO2 ESB también tiene soporte completo para exponer API REST. Esta

característica es la que centra este artículo, todo el trabajo de implementación aquí

descrito gira en torno a la exposición de servicios REST en WSO2 ESB.

2.2. Soporte API REST en WSO2 ESB.

Un API REST de WSO2 ESB es análogo a una aplicación web desplegada en el

runtime del ESB. Cada API está configurada con un contexto, definido por el usuario

con una URL. Este método de funcionamiento es muy similar a cómo funciona una

aplicación web desplegada en un contenedor de servlets6 que está vinculado en un

contexto con una URL fija. La API sólo procesará las solicitudes que entren mediante

4 http://wso2.com/products/enterprise-service-bus/ 5 http://wso2.com/products/application-server/ 6 http://www.oracle.com/technetwork/java/index-jsp-135475.html

Page 6: Chakray howto get cup of coffee the wso2 way español

6

Por Juanjo Hernández IT Consultant

el uso de la URL de su contexto. Por ejemplo, si una API tiene vinculado el contexto "/

test", sólo aquellas solicitudes HTTP cuya ruta URL comienza con "/ test" serán

“manejados” por esa API. Incluso es posible enlazar un API dado a un nombre de host

y o un número de puerto definido por el usuario.

WSO2 desde su versión 4.0.3 es capaz de manejar, mediar y exponer una API REST,

por lo que nuestro ejemplo, funcionará de la siguiente manera.

Ilustración 1. REST TO SOAP Mediación ESB

También es posible que pese que ambos entornos funcionen bajo los principios REST

la respuesta tenga que ser transformada en un formato que sea entendible por ambas

partes Cliente/Servidor, el ESB media en el mensaje y permite la comunicación entre

ambos participantes, a esto se le llama Content Negotiation y representa la capacidad

del ESB de cambiar el formato del mensaje de tal manera que pueda ser entendido

por ambas partes tras la modificación.

Ilustración 2. Transformación de mensajes REST con ESB

Page 7: Chakray howto get cup of coffee the wso2 way español

7

Por Juanjo Hernández IT Consultant

Continuando con la explicación de cómo WSO2 ESB da cobertura a las API REST,

empezaremos introduciendo el concepto de resource7. Un API REST está formado por

uno o más recursos. Desde un punto de vista de arquitectura, un recurso es un

componente lógico de una API que se puede acceder al hacer un tipo particular de

llamadas HTTP. Desde un punto de vista más pragmático, un resource es similar a un

proxy service. Al igual que un proxy service, un resource también contiene una in-

sequence, una out-sequence y una fault-sequence. Los mediadores disponibles son

los mismos y su funcionamiento idéntico. Pero también hay varias diferencias

significativas entre los resources y los proxy services, un resource sólo puede ser

utilizado para recibir y procesar llamadas REST, mientras que un proxy service puede

recibir todo tipo de peticiones. Un resource tampoco puede publicar un WSDL ni otros

WS-* (módulos de seguridad, mensajería fiable, etc).

Como hemos comentado anteriormente cada resource puede ser asociado con un

patrón de URL definido por el usuario o una plantilla URI. Esta metodología puede

restringir el tipo de petición HTTP procesada por un resource en particular. Además un

resource también puede estar limitado a un subconjunto de acciones HTTP (GET,

PUT, POST, DELETE…) o valores de cabecera. Esta opción añade un control

adicional sobre cómo las peticiones son manejadas por un resource dado.

Por ejemplo vamos a considerar un resource asociado con el patrón de URL “/foo/” y la

acción HTTP GET. Esta configuración nos asegura que dicho resource solo será

procesado cuando se realicen peticiones GET las cuales coincidan con el patrón del

path de la URL “/foo/, por lo tanto las siguientes peticiones serán procesadas y

mediadas por el resource configurado en la api:

GET /test/foo/bar

GET/test/foo/a?arg1=hello

Y las siguientes peticiones no serán procesadas por ese resource:

GET /test/food/bar (URL pattern not matching)

POST /test/foo/bar (HTTP verb not matching)

7 Se ha optado por convención no traducir los elementos de la sintaxis ESB con el fin de simplificar la implantación.

Page 8: Chakray howto get cup of coffee the wso2 way español

8

Por Juanjo Hernández IT Consultant

Una vez que la petición se envía al resource será mediada a través de la in-sequence

del recurso. Al final de la in-sequence la solicitud será enviada a la aplicación de back-

end para su posterior proceso. Las respuestas provenientes del sistema de back-end

será mediadas por la API en el ESB a través de la out-sequence del resource.

Para terminar la explicación del funcionamiento de un resource configurado en una

API comentar que la fault-sequence sirve para controlar los errores que se produzcan

durante la mediación del mensaje en el resource.

Para entender mejor cómo funciona la gestión de las solicitudes (request) entre las API

y los resources, vamos a considerar la siguiente jerarquía de objetos:

Ilustración 3. Configuración de contextos y plantillas de URL en resource.

Aquí tenemos dos APIs REST configuradas para los contextos “/foo” y “/bar”

respectivamente. Cada API habilita dos resources. La petición GET del path “/foo/test”

será recibida por la primera API1 ya que responde a este contexto. Esta API1 maneja

dos recursos uno para GET y otro para POST, cuando se realice una petición GET

será el resource A el que gestionará y mediará el mensaje y cuando se realice una

petición POST será el resource B el que cogerá la batuta en el manejo del flujo. De

Page 9: Chakray howto get cup of coffee the wso2 way español

9

Por Juanjo Hernández IT Consultant

idéntica manera funcionará la API2, que tiene un contexto “/bar”, todas la peticiones

que se realicen bajo ese concepto serán redirigidas a esta API y según la petición y,

en este caso también, el path de la url, el mensaje será mediado por el resource C o

resource D (peticiones PUT con path /bar/test será mediado por resource C y

peticiones DELETE con path /bar/abc será mediado por resource D).

Todo lo anteriormente mencionado, explica la gran utilidad del uso de las

características de las API REST en WSO2 ESB.

En pocas palabras, se proporciona un método simple pero muy potente para romper el

flujo de llamadas HTTP basado en: métodos HTTP, patrones de URL y otros

parámetros. Una vez que las llamadas HTTP han sido filtradas y enviadas a las API y

a sus resources pertinentes, podemos someterlos a las capacidades de enrutamiento

y de mediación del ESB utilizando mediators, sequences y endpoints.

2.3. Mapeos de la URL y plantillas URI.

Cómo hemos comentado en el apartado anterior un resource puede estar asociado

con un mapeo de URL o con una plantilla URI. Un mapeo URL puede ser cualquier

mapeo de servlet válido, por lo tanto y siguiendo las especificaciones servlet, hay tres

tipo de mapeos URL:

Mapeo del path: /test*, /foo/bar/* Mapeo por extensions *.jsp, *.do Mapeo exacto /test, /test/foo

Cuando un resource está definido con un Mapeo de URL de los anteriormente

comentados, solo aquellas peticiones que coincidan con el mapeo serán procesadas

por el resource. Alternativamente se puede configurar un resource con una plantilla

URI. Una plantilla URI representa una clase de URI que usa patrones y variables,

algún ejemplo de plantillas de URIs válidas serían:

/order/{orderId}

/dictionary/{char}/{word}

Page 10: Chakray howto get cup of coffee the wso2 way español

10

Por Juanjo Hernández IT Consultant

Los identificadores entre llaves son consideradas variables. Un ejemplo de URL que

coincidiría con uno de los templates anteriores sería: /order/A001

En la URL anterior a la variable orderId se le ha asignado el valor “A0001”. De forma

similar la siguiente URL: /dictionary/c/cat coincide con la plantilla

“/dictionary/{char}/{Word}”. En este caso la variable “char” asume el valor “c” y la

variable “word” el valor “cat”.

El caso en que un resource se asocia con una plantilla URI, todas las peticiones que

coincidan con la plantilla serán procesadas por el resource. Al mismo tiempo el ESB

proporcionará acceso a los valores de las variables configuradas en la plantilla a

través de las propiedades de contexto del mensaje. Siguiendo con el ejemplo de la

plantilla URI anteriormente comentada "/dictionary/{char}/{word}", cuando la solicitud

"/dictionary/c/cat" se envíe al ESB, el recurso arriba mencionado será capaz de

recuperar los valores exactos usando la extensión XPath de WSO2 ESB y más

concretamente con el método get-property. Por ejemplo para escribir en el log los

valores recuperados en la petición de la siguiente manera utilizando el log mediator

<log level="custom">

<property name="Character" expression="get-property('uri.var.char')"/>

<property name="Word" expression="get-property('uri.var.word')"/>

</log>

2.4. Configuración de APIs y resources en el ESB.

Ahora que hemos conseguido una básica comprensión de cómo funcionan las APIs

REST en WSO2 ESB, vamos a echar un vistazo a cómo podemos configurar una API

en el Bus usando el lenguaje de configuración del ESB.

La definición de una API se identifica por el tag <api>. Cada API debe tener un nombre

y un contexto de URL únicos. Algunos ejemplos de definiciones de APIs:

<api name="API_1" context="/order">

<resource url-mapping="/list" inSequence="seq1" outSequence="seq2"/>

</api>

Page 11: Chakray howto get cup of coffee the wso2 way español

11

Por Juanjo Hernández IT Consultant

<api name="API_2" context="/user">

<resource url-mapping="/list" methods="GET" inSequence="seq3" outSequence="seq4"/>

<resource uri-template="/edit/{userId}" methods="PUT POST" inSequence="seq5"

outSequence="seq6"/>

</api>

<api name="API_3" context="/payments">

<resource url-mapping="/list" methods="GET" inSequence="seq7" outSequence="seq8"/>

<resource uri-template="/edit/{userId}" methods="PUT POST" outSequence="seq9">

<inSequence>

<log/>

<send>

<endpoint key="BackendService"/>

</send>

</inSequence>

</resource>

<resource inSequence="seq10" outSequence="seq11"/>

</api>

Si observamos la última definición del resource en la API_3, no se especifica un

mapeo URL ni tampoco una plantilla URI. La llamada a este resource se realizará por

defecto cuando la petición no cumpla ninguna de las condiciones anteriores. Cada API

puede tener como máximo un resource por defecto. En el ejemplo de la API_3 una

petición DELETE8 para la URL “/payments” será tratada por el resource por defecto ya

que ninguno de los otros está configurado para aceptar peticiones DELETE.

3. Diseño de la Solución “Starbucks”.

Ahora ya tenemos suficiente base de conocimiento de WSO2 AS y WSO2 ESB para

empezar, si se desea profundizar más se puede consultar la documentación de WSO2

ESB9. Vamos a implementar la solución RESTful que describe Jim Webber10 en su

artículo “How to GET a Cup of Coffee11” usando las tecnologías WSO2, es muy

recomendable leerse ese artículo antes de continuar para entender la solución

funcional que propone el autor y de esta manera entender ampliamente lo que aquí se

explica.

8 En estos momentos, DELETE no está implementado en este documento. 9 Un punto inicial de consulta es: https://docs.wso2.org/display/ESB480/Getting+Started+with+REST+APIs 10 http://jimwebber.org/ 11 http://www.infoq.com/articles/webber-rest-workflow/

Page 12: Chakray howto get cup of coffee the wso2 way español

12

Por Juanjo Hernández IT Consultant

La aplicación Starbucks12 descrita en el artículo de Jim Webber consiste en dos

máquinas diferentes:

• Customer state machine (Máquina de estado de Cliente) • Barista state machine (Máquina de estado de Barista13)

La máquina de estado de Cliente consiste en las siguientes interacciones:

• El cliente efectúa el pedido de una bebida. • El cliente realiza cambios en un pedido ya efectuado (p.e. pedir un condimento

para que sea añadido). • El cliente realiza e pago del pedido.

Por otra parte, la máquina de estado de Barista se compone de las siguientes interacciones:

• Recuperar una lista de los pedidos pendientes. • Comprobar si se ha recibido el pago de un pedido en particular • Borrar los pedidos ya emitidos de la lista de pedidos pendientes.

Basándonos en los detalles anteriores, podemos identificar tres aplicaciones principales involucradas en la solución:

• Aplicación de Cliente14 • Aplicación de Barista • Starbucks OMS (Order Management System o Sistema Gestor de Pedidos)

La Aplicación de Cliente deberá interactuar con el OMS de Starbucks para añadir los

pedidos y hacer los pagos. De una manera similar la Aplicación de Barista deberá

comunicar con el OMS para obtener la lista de las órdenes pendientes y comprobar los

estados de pago de lo cada pedido requerido. Con esto en mente podemos llegar a

dar a este escenario una solución de arquitectura de alto nivel, como la siguiente:

12 Cadena de cafeterías con puntos de venta en todo el mundo. http://www.starbucks.com 13 Barista: Profesional especializado en el café de alta calidad, que trabaja creando nuevas y diferentes bebidas basadas en él, usando varios tipos de leches, esencias y licores, entre otros. También es el responsable de la presentación de las bebidas y puede complementar su trabajo con arte del latte. (Extraído de Wikipedia) 14 Cliente en este caso lo entendemos como persona que realiza un pedido en una cafetería de Starbucks y no como aplicación cliente TIC.

Page 13: Chakray howto get cup of coffee the wso2 way español

13

Por Juanjo Hernández IT Consultant

Ilustración 4. Solución de arquitectura de alto nivel.

En el actual ejemplo no vamos a prestar atención a la implementación de las 3

aplicaciones, nosotros estamos más interesados en cómo las aplicaciones interactúan

entre ellas usando un modelo de comunicación RESTful. Para la aplicación Starbucks

OMS vamos a usar una aplicación simple Web Service de Java la cual estará alojada

en el servidor de aplicaciones (WSO2 AS) y que expone una capa de servicios SOAP.

Todos los detalles de los pedidos se almacenan en una tabla en memoria, no vamos a

utilizar base de datos o ficheros en este ejemplo para la persistencia, aunque como es

normal si fuera una aplicación para ser usada en un escenario real el almacenamiento

de la información y toda la capa de datos requeriría un análisis diferenciado.

Para simular la Aplicación de Cliente y la Aplicación de Barista vamos a usar cURL15,

que, para quien no la conozca, es una herramienta cliente muy simple de HTTP que

nos permite realizar las llamadas a la capa REST usando cualquier tipo de petición y

modificando los tipos de contenido (Content Type) que vamos a transmitir. Aun así

existen un par de aplicaciones simples realizadas con Java con una interfaz más

amigable y que simularían los comportamientos de la Aplicación de Cliente y de

Barista.

Cómo nuestra Aplicación OMS de Starbucks está basada en SOAP tenemos que

desarrollar el método de conversión de REST a SOAP y es por este motivo que

vamos a usar WSO2 ESB. Expondremos un conjunto de APIs REST en el ESB. Las

Aplicaciones de Cliente y de Barista interaccionarán con estas APIs realizando

invocaciones RESTful. Posteriormente el ESB “traducirá” las llamadas REST a SOAP

mediando los mensajes y realizará las invocaciones pertinentes al OMS que se

15 http://curl.haxx.se/

Page 14: Chakray howto get cup of coffee the wso2 way español

14

Por Juanjo Hernández IT Consultant

encuentra en el servidor de aplicaciones de WSO2 (AS). Con esta información

podemos mejorar el diagrama de la arquitectura de la siguiente manera:

Ilustración 5. Solución de arquitectura con ESB.

Esta solución, además de servirnos para el diseño del sistema RESTful, nos enseñará

cómo exponer un sistema existente sobre REST. Básicamente tomamos el OMS

Starbucks basado en SOAP y le aplicamos una capa RESTful sobre él. La misma

técnica se puede ampliar para exponer cualquier aplicación a través de REST. Muchas

organizaciones cuentan con servicios y aplicaciones legacy que necesitan ser

expuestos sobre REST para que puedan ser fácilmente consumidos por los

navegadores web y apps móviles actuales. Este artículo y el ejemplo que trata

pretenden proporcionar la base para la gestión de cualquier escenario similar.

4. Configuración de los servidores

En el artículo original de Mr. Hiranya Jayathilaka se usaron las versiones de productos

que por aquel entonces (septiembre 2012) WSO2 tenía, en este ejemplo nos hemos

basado en las versiones que actualmente están disponibles y son WSO2 AS 5.2.1 y

WSO2 ESB 4.8.1. Para instalar los servidores y permitir que corran la máquina en la

que realicemos la práctica debemos cambiar el parámetro Offset de nuestro archivo

carbon.xml que se encuentra en: repository/conf/carbon.xml de la siguiente manera:

<Ports>

<Offset>1</Offset>

[…]

</Ports>

Para cada servidor necesitamos cambiar el Offset, para los recién llegados a la suite

de aplicaciones middleware de WSO2 comentar únicamente que el número introducido

Page 15: Chakray howto get cup of coffee the wso2 way español

15

Por Juanjo Hernández IT Consultant

en Offset incrementa el puerto por defecto en el que corren los servidores en el

número en cuestión. Es decir si el servidor corre en el puerto https 9443 por defecto,

un Offset de 1 haría que el servidor corriera en el puerto 9444 y un Offset de 3 haría

que corriera en el puerto 9446 lo que evitaría posibles conflictos de puertos ocupados

al arrancar.

Una vez realizado esto y arrancadas ambas máquinas, ejecutando el script

wso2server que se encuentra en el directorio bin de cada instalación, instalaremos

inicialmente la Aplicación Starbucks OMS en el WSO2 AS. Para ello nos

identificaremos en la zona de administración del AS en

https://localhost:9443[+Offset]/carbon, haremos clic en Services>Add>AAR Service del

menú Manage y lo subiremos el archivo StarbucksOutletService.aar16.

Ilustración 6. Añadir Servicios Starbucks back-end en WSO2 AS.

Tras algunos segundos de despliegue ya tienes disponible la Aplicación Starbucks

OMS, haciendo clic en Services>List puedes ver un nuevo servicio llamado

StarbucksOutletService en el servidor.

16 https://www.dropbox.com/s/b3leesblvkm2eyg/StarbucksOutletService.aar

Page 16: Chakray howto get cup of coffee the wso2 way español

16

Por Juanjo Hernández IT Consultant

Ilustración 7. Lista de servicios desplegados.

Ilustración 8. Detalle del servicio Starbucks OMS desplegado.

Page 17: Chakray howto get cup of coffee the wso2 way español

17

Por Juanjo Hernández IT Consultant

Para realizar las pruebas funcionales previas se puede usar un cliente SOAP

cualquiera como SOAP UI17 para interactuar con los servicios y sus acciones, también

con la opción Try-It del propio AS de WSO2 se podría invocar el servicio y probarlo.

5. Implementación.

5.1. Realizando nuevos pedidos.

Comenzamos con la implementación de la API REST responsable de aceptar nuevos

pedidos. El back-end OMS de Starbucks proporciona una operación addOrder que

permite el manejo de esta tarea. De esta manera nuestra API REST debería al final,

invocar esta operación para realizar la funcionalidad. Podemos llamar a nuestra API

“StarbucksOrderAPI” y referenciarla al contexto “/order” como sigue:

<api name="StarbucksOrderAPI" context="/order"> […] </api>

Conforme el mencionado artículo de Jim Webber, un nuevo pedido es enviado usando

una llamada HTTP POST a la URL de contexto “/order”, entonces y según hemos

vistos en capítulos anteriores tenemos que definir un resource en nuestra nueva API

para aceptar peticiones POST, tal que así:

<api name="StarbucksOrderAPI" context="/order"> <resource url-mapping="/" methods="POST"> […] </resource> </api>

Ahora podemos avanzar en la implementación de la in-sequence y la out-sequence del

resource anterior. La in-sequence debe construir el mensaje SOAP esperado por la

operación addOrder del Starbucks OMS e invocar esa operación.

<inSequence> <property name="STARBUCKS_HOST_NAME" expression="$axis2:SERVICE_PREFIX" /> <payloadFactory> <format> <m0:addOrder> <m0:drinkName>$1</m0:drinkName> <m0:additions>$2</m0:additions> </m0:addOrder> </format>

17 http://www.soapui.org/

Page 18: Chakray howto get cup of coffee the wso2 way español

18

Por Juanjo Hernández IT Consultant

<args> <arg expression="//sb:drink" /> <arg expression="//sb:additions" /> </args> </payloadFactory> <send> <endpoint key="DataServiceEndpoint" /> </send> </inSequence>

Por otra parte la out-sequence debe transformar la respuesta SOAP en un formato de

mensaje RESTful aceptado, establecer el código de estado conveniente y pasar el

mensaje al cliente:

<outSequence> <property name="HTTP_SC" value="201" scope="axis2" /> <property name="uri.var.orderId" expression="//m1:orderId"/> <sequence key="StarbucksOrderInfo" /> <send /> </outSequence>

El fichero de configuración completo de la API de este artículo está disponible y te lo

puedes descargar, este es el fichero en cuestión: synapse-configs.zip18. Basta con

extraer cada fichero xml en su carpeta específico a partir del directorio del servidor,

repository/deployment/server/synapse-configs/default del ESB y substituir la

configuración existente con la descargada del presente ejemplo. Recordad que se

debe reiniciar el servidor. Una vez descargado y desplegado correctamente, puedes

invocar la StarbucksOrderAPI y probarla. Si estás usando Curl, puedes crear un

fichero llamado order.xml con el siguiente contenido,

<?xml version="1.0" encoding="UTF-8"?> <order xmlns="http://starbucks.example.org"> <drink>Caffe Misto</drink> </order>

posteriormente usando el siguiente comando:

curl -v -d @order.xml -H "Content-type: application/xml" http://localhost:8281/order

La respuesta debe ser algo similar a: POST /order HTTP/1.1 Transfer-Encoding: chunked Content-Type: application/xml Host: 127.0.0.1:8281 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.1.2 (java 1.5) <?xml version="1.0" encoding="UTF-8"?>

18 https://www.dropbox.com/sh/rggaomh9d3f0aym/bUo3nQA1GD

Page 19: Chakray howto get cup of coffee the wso2 way español

19

Por Juanjo Hernández IT Consultant

<order xmlns="http://starbucks.example.org"> <drink>Caffe Misto</drink> </order> HTTP/1.1 201 Created Content-Type: application/xml; charset=UTF-8 Location: http://127.0.0.1:8281/order/7b36032d-6aa2-4d77-90a9-7473a42de77b Server: WSO2 Carbon Server Vary: Accept-Encoding Date: Wed, 15 Aug 2012 12:55:50 GMT Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <order xmlns="http://starbucks.example.org"> <drink>Caffe Misto</drink> <cost>6.99</cost> <additions/> <next rel="http://127.0.0.1:8281/payment" type="application/xml" uri="http://127.0.0.1:8281/payment/order/7b36032d-6aa2-4d77-90a9-7473a42de77b" xmlns="http://example.org/state-machine"/> </order>

Esta orden realiza la petición POST para introducir un Pedido en el sistema Starbucks

OMS desde nuestro cliente que envía REST y tras pasar por el ESB transformado a

SOAP y la respuesta que proviene del Starbucks OMS que originalmente es SOAP

transformada en REST/POX para que sea aceptada por el cliente.

En este punto se debe comentar que según la versión actual del ESB (que usa Axis2

para gestionar los servicios) es necesario realizar algunas modificaciones en la

implementación de la API que Mr. Hiranya Jayathilaka no aplicaba seguramente

porque la versión del ESB/Axis no se lo exigía. Es necesario añadir un mediador del

tipo property tras la manipulación del mensaje y antes de realizar el envío del mismo

formateado al Starbucks OMS. Esta propiedad que se debe incluir debe especificar

qué operación SOAP (SOAPAction) va a invocarse en la llamada de la siguiente

manera: <property name="SOAPAction" value="urn:updateOrder" scope="transport"></property>

Esta pequeña modificación es necesaria para no recibir el molesto y poco amigable

error:

Caused by: org.apache.axiom.soap.SOAPProcessingException: First Element must contain the local name, Envelope , but found faultstring

Continuamos con la configuración de la API e intentar entender cómo funciona. La

primera cosa que nos encontramos es el siguiente mediador del tipo property y que se

usa en la in-sequence: <property name="STARBUCKS_HOST_NAME" expression="$axis2:SERVICE_PREFIX" />

Page 20: Chakray howto get cup of coffee the wso2 way español

20

Por Juanjo Hernández IT Consultant

SERVICE_PREFIX es una propiedad disponible en el flujo de mensajes del ESB.

Establecida en el ámbito axis2, esta propiedad contiene el segmento

[protocolo]://[host]:[port] de la URL que será invocado por el cliente.

Por ejemplo, si el usuario envía una petición a la URL http://localhost:8280/foo/bar,

entonces la propiedad anterior contendrá el valor http://localhost:8280/. Usando el

mediador property anterior asignamos ese valor a una nueva propiedad llamada

STARBUCKS_HOST_NAME. Esto lo hacemos así porque tenemos la intención de

utilizar este valor más adelante en la creación de la respuesta que posteriormente

debe ser enviada al cliente.

Tras esto vemos otro mediador llamado payloadFactory. Este mediador es usado para

construir el mensaje SOAP que necesita ser enviado al OMS de Starbucks. Para poder

extraer la información del mensaje usamos expresiones XPath19 sobre la petición

original para extraer algunos de sus valores y usarlos en la construcción del nuevo

mensaje que ejecutará la acción addOrder.

Finalmente en el mismo apartado in-sequence se usa un mediador del tipo send con

un endpoint. Aquí es donde realizamos las llamadas al back end OMS de Starbucks

según la configuración de tu Offset la definición del endpoint sería: <endpoint name="DataServiceEndpoint" xmlns="http://ws.apache.org/ns/synapse"> <address uri=http://localhost:9763/services/StarbucksOutletService format="soap12"/> </endpoint>

Cómo apunte podemos observar el atributo soap12. Esto informa al ESB que todos los

mensajes enviados al endpoint del OMS deberían ser en formato SOAP 1.2, por lo

tanto el ESB envolverá el mensaje XML en un envoltorio (envelope) SOAP 1.2 antes

de enviarlo al servicio SOAP back-end.

Si todo funciona correctamente, nuestro ESB recibirá a continuación la respuesta

SOAP de nuestro AS. Apuntar cómo el back-end OMS ha generado un ID único para

nuestro pedido. Este mensaje SOAP será mediado a través de la out-sequence del

resource apropiado en la API. En nuestra out-sequence tenemos la siguiente instancia

de mediador de tipo property como primera entrada: <property name="HTTP_SC" value="201" scope="axis2" />

19 http://www.w3.org/TR/xpath20/

Page 21: Chakray howto get cup of coffee the wso2 way español

21

Por Juanjo Hernández IT Consultant

Este mediador cambia el código de estado HTTP de la respuesta. De acuerdo con los

principios de diseño RESTful tendríamos que envíar una respuesta con código de

estado 201 Created en este escenario. Pero nosotros obtenemos del back-end OMS el

típico mensaje 200 “OK” que es el comportamiento SOAP habitual. Esta configuración

del mediador cambia el estado a 201 Created para que el cliente reciba la respuesta

correcta.

Continuado con el diseño de una arquitectura de servicios RESTful correcta, es

también muy importante enviar una cabecera Location junto con la respuesta 201

Created. Esta cabecera debe contener una URL válida que apunte de nuevo al recurso

que se ha creado en el sistema back-end, por lo tanto en nuestro escenario la

cabecera Location debe contener una URL mediante la cual podemos obtener una

descripción del pedido que acabamos de crear. El siguiente mediador property se

encuentra en la sequence “StarbucksOrderIndo” y es usado para añadir la cabecera

Location para la respuesta “saliente”. <property name="Location" expression="concat($ctx:STARBUCKS_HOST_NAME, 'order/', //m1:orderId)" scope="transport" />

Como puedes ver aquí usamos la propiedad que inicializamos anteriormente en la in-

sequence para poder recuperarla cuando fuera necesario

STARBUCKS_HOST_NAME. Simplemente recuperamos el valor de esta propiedad y

le añadimos el fragmento “/order/orderId” para construir la URL completa.

La construcción de respuestas que contienen direcciones URL a los diferentes

recursos relacionados es de suma importancia en una arquitectura de aplicaciones

REST.

Esto facilita particularmente la navegación y las transiciones de estados en una

aplicación que siga el paradigma de integración REST. La respuesta de una llamada

REST debe contener toda la información que un cliente requeriría para navegar y

proceder con el siguiente paso dentro de la aplicación, de esta manera el cliente

puede comenzar con una única URL conocida y navegar toda la aplicación siguiendo

las URLs incluidas en cada respuesta. A este concepto se le denomina a menudo

como HATEOAS (Hypermedia as the Engine of Application State). Es interesante que

reflexionemos sobre cómo hemos incorporado esta función en nuestra solución

utilizando las capacidades de mediación de WSO2 ESB. La respuesta a la solicitud de

Page 22: Chakray howto get cup of coffee the wso2 way español

22

Por Juanjo Hernández IT Consultant

creación del pedido contiene una cabecera Location que apunta de nuevo al recurso

pedido. También el mensaje de respuesta contiene más direcciones URL para que las

acciones de Pago de Pedido se encarguen de su tramitación. Usando la propiedad

SERVICE_PREFIX incorporada en el ESB construimos todas los URLs para que todas

apunten de nuevo al ESB. En ningún momento se exponen los detalles del endpoint

del servicio web del back-end OMS.

5.2. Revisando pedidos.

Una vez el pedido ha sido añadido al sistema, el cliente debería ser capaz de revisarlo.

Esto se puede hacer enviando peticiones HTTP GET a la URL especificada en la

respuesta 201 Created que comentábamos en el capítulo anterior. Tal y como se ha

explicado y siguiendo el paradigma HATEOAS la misma respuesta de la creación del

nuevo pedido incorpora la URL que permitió esa acción.

En la configuración de nuestra API hemos definido un resource separado para

procesar las peticiones GET. <resource uri-template="/{orderId}" methods="GET PUT OPTIONS" faultSequence="StarbuckFault">

Hemos usado una plantilla URI para especificar el formato de la petición URL entrante

que esperamos. La parte orderId de la URL ha sido especificada como variable porque

cada orden tendrá su identificador único. En la in-sequence construimos un mensaje

getOrder SOAP usando el mediador payloadFactor. Es aquí donde utilizaremos la

variable orderId. <payloadFactory> <format> <m0:getOrder> <m0:orderId>$1</m0:orderId> </m0:getOrder> </format> <args> <arg expression="$ctx:uri.var.orderId" /> </args> </payloadFactory>

La respuesta de la aplicación Starbucks OMS será un mensaje SOAP que contendrá

los detalles del pedido. Simplemente convertimos en un documento POX (plain old

XML) y lo devolvemos al cliente como una respuesta RESTful. Para probar el

escenario, debemos localizar un orderId de un pedido realizado anteriormente (se

puede conseguir de la cabecera Location de la respuesta al realizar una petición de

Page 23: Chakray howto get cup of coffee the wso2 way español

23

Por Juanjo Hernández IT Consultant

creación de nuevo Pedido) y ejecutar Curl como sigue (reemplazando my-order-id, por

el identificador del pedido, orderId, conseguido) curl -v http://localhost:8281/order/my-order-id

Llegados a este punto es un buen momento para demostrar las capacidades de

manejo de errores del ESB. Si ejecutamos la siguiente orden Curl como sigue con un

ID incorrecto: curl -v http://localhost:8281/order/bogus-order-id

El OMS de Starbucks devolverá un mensaje vacío al ESB. Veamos, la out-sequence

que corresponde al resource de la API ha sido configurado para detectar esta

condición y responder un estado HTTP 404 Not Found response. Por lo tanto si

intentas ejecutar el comando anterior se devolverá algo similar a lo siguiente: HTTP/1.1 404 Not Found Content-Type: application/xml; charset=UTF-8 Server: WSO2 Carbon Server Date: Wed, 15 Aug 2012 13:10:10 GMT Transfer-Encoding: chunked <message xmlns="http://starbucks.example.org"><text>No order exists by the specified ID</text></message>

5.3. Realizando pagos.

Vamos a saltarnos un par de pasos y ver cómo se manejan los pagos en nuestra

solución. En el artículo de Webber, los pagos son tratados como un grupo separado de

varios resource.

En nuestra implementación manejamos los pagos mediante una API separada. Vamos

a llamar a esta API StarbucksPaymentAPI y asociarle el contexto “/payment”. El cliente

puede crear un pago enviando una petición del tipo PUT a la URL

http://localhost:8281/payment/order/orderId. El mensaje de la llamada debe contener

toda la información requerida para el pago así como el precio total y los detalles de la

tarjeta de crédito.

<resource

uri-template="/order/{orderId}"

methods="GET PUT"

faultSequence="StarbucksFault">

Observar que el resource ha sido configurado para el manejo de las peticiones PUT. El

resource, como ya hemos explicado, transformará el mensaje entrante en un mensaje

SOAP e invocará al back-end Starbucks OMS. La respuesta será transformada en su

Page 24: Chakray howto get cup of coffee the wso2 way español

24

Por Juanjo Hernández IT Consultant

regreso a un mensaje POX y enviada al cliente con un estado de respuesta 201

Created.

Tal y como hemos hecho en todas las operaciones anteriores y para seguir con el

diseño correcto de una arquitectura REST es conveniente añadir en la cabecera de la

respuesta un mediador property llamado Location que apuntará a la URL invocadora

perteneciente al resource de pago.

Para probar esta API podemos crear un fichero XML llamado payment.xml con la

siguiente información: <?xml version="1.0" encoding="UTF-8"?> <payment xmlns="http://starbucks.example.org"> <cardNo>1234-5678-9010</cardNo> <expires>12/15</expires> <name>Peter Parker</name> <amount>6.99</amount> </payment>

Ahora lo ejecutamos con el siguiente comando Curl (sustituyendo como anteriormente

el order-id por un id de un pedido real) curl -v -X PUT -d @payment.xml -H "Content-type: application/xml" http://localhost:8281/payment/order/order-id

La respuesta debería ser algo similar a: HTTP/1.1 201 Created Content-Type: application/xml; charset=UTF-8 Location: http://127.0.0.1:8281/payment/order/090abb1b-9da0-4eb3-86c1-02c7fa157514 Server: WSO2 Carbon Server Date: Wed, 15 Aug 2012 13:12:15 GMT Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <payment xmlns="http://starbucks.example.org/"> <cardNo>1234-5678-9010</cardNo> <expires>12/15</expires> <name>Peter Parker</name> <amount>6.99</amount> </payment>

Una vez el pago ha sido realizado, el cliente puede revisar los detalles del pago

realizando una petición GET. Recordad que para revisar el estado necesitamos el Id

único de la orden que se ha pagado en el punto anterior y ejecutar la siguiente orden

Curl (sustituye de nuevo order-id por el id real de la orden pagada que se quiere

revisar). curl -v http://localhost:8281/payment/order/order-id HTTP/1.1 200 OK Content-Type: application/xml; charset=UTF-8 Server: WSO2 Carbon Server

Page 25: Chakray howto get cup of coffee the wso2 way español

25

Por Juanjo Hernández IT Consultant

Date: Wed, 15 Aug 2012 13:17:39 GMT Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <payment xmlns="http://starbucks.example.org/"> <cardNo>1234-5678-9010</cardNo> <expires>12/15</expires> <name>Peter Parker</name> <amount>6.99</amount> </payment>

La Aplicación de Barista de Starbucks puede usar la característica anterior para

comprobar si un pedido ha sido pagado antes de que la bebida haya sido entregada al

cliente. Si el pago no ha sido hecho para un pedido en concreto, la API devolverá una

respuesta con el error 404 Not Found.

5.4. Manejando actualizaciones de pedidos.

Todos hemos ido a tomar un café en algún momento y aunque hemos pedido un café

solo, luego creemos que sería mejor dejar la cafeína por un día y tomar otra cosa por

ejemplo, un zumo. Nuestro sistema debe permitir al cliente realizar este tipo de

rectificaciones, pero ¿Qué pasa si ya ha comenzado el Barista a preparar nuestro

pedido? Entonces nuestro sistema no nos permitirá modificarlo y un sonriente

camarero nos dirá: “lo siento pero su pedido ya ha sido realizado”. Por lo tanto nuestra

solución debe permitir modificaciones en los pedidos hasta que el Barista haya

comenzado la preparación.

En el artículo original, Mr. Jim Webber propone usar el método HTTP OPTIONS de

manera que comprobemos cuando un pedido es modificable o no. Una simple petición

OPTIONS de una orden debería devolver en la respuesta una cabecera HTTP Allow.

Si el pedido aún se puede cambiar la cabecera Allow debería incluir dos valores GET y

PUT, sin embargo si el pedido ya ha pasado a realización y por lo tanto no se puede

modificar, únicamente debería devolver el valor GET que significa que ese pedido es

de “solo lectura”.

Permitir este requisito en nuestra implementación es fácil. Simplemente se debe añadir

el método OPTIONS a la lista de métodos soportados por el resource getOrder de la

siguiente manera: <resource uri-template="/{orderId}" methods="GET PUT OPTIONS" faultSequence="StarbuckFault">

Page 26: Chakray howto get cup of coffee the wso2 way español

26

Por Juanjo Hernández IT Consultant

Un simple switch case puede filtrar del todo las llamadas OPTIONS en el resource: <switch source="$ctx:REST_METHOD"> <case regex="OPTIONS"> <property name="NO_ENTITY_BODY" value="true" scope="axis2" type="BOOLEAN" /> <filter source="//m1:locked" regex="false"> <then> <property name="Allow" value="GET,PUT" scope="transport" /> </then> <else> <property name="Allow" value="GET" scope="transport" /> </else> </filter> </case> […] </switch>

El resource puede, entonces, consultar el OMS para comprobar si el pedido es

modificable o no, dependiendo de la respuesta del back-end, se podrá realizar una

respuesta HTTP apropiada en el ESB.

Realiza la prueba con el siguiente comando Curl (cómo siempre sustituye order-id por

un Id de pedido original) curl -v -X OPTIONS http://localhost:8281/order/order-id

Si la orden es modificable, la respuesta que se realizará debe ser algo similar a: HTTP/1.1 200 OK Allow: GET,PUT Server: WSO2 Carbon Server Date: Wed, 15 Aug 2012 13:22:36 GMT Content-Length: 0 Connection: Keep-Alive

Las actualizaciones de los pedidos se llevan a cabo haciendo llamadas HTTP PUT. El

mensaje de la petición debe contener una descripción de la actualización de la orden.

Hemos configurado nuestro resource en la API para manejar las invocaciones PUT de

la siguiente manera: <resource uri-template="/{orderId}" methods="GET PUT OPTIONS" faultSequence="StarbuckFault">

Para probar esta operación copia el siguiente xml en un fichero llamado update.xml y

ejecútalo con el Comando Curl que aparece a continuación (no te olvides, sustituye de

nuevo order-id por el id del pedido real) <?xml version="1.0" encoding="UTF-8"?> <order xmlns="http://starbucks.example.org"> <drink>Caffe Misto</drink> <additions>Milk</additions> </order>

curl -v -X PUT -d @update.xml -H "Content-type: application/xml" http://localhost:8281/order/order-id

Page 27: Chakray howto get cup of coffee the wso2 way español

27

Por Juanjo Hernández IT Consultant

Si todo va bien, se debe recibir un estado HTTP 200 confirmando la actualización del

pedido parecido a: HTTP/1.1 200 OK Content-Type: application/xml; charset=UTF-8 Location: http://127.0.0.1:8281/order/764cc8b5-e612-47e1-818b-225cb35b0c3f Server: WSO2 Carbon Server Date: Wed, 15 Aug 2012 13:24:48 GMT Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <order xmlns="http://starbucks.example.org"> <drink>Caffe Misto</drink> <cost>10.71</cost> <additions>Milk</additions> <next rel="http://127.0.0.1:8281/payment" type="application/xml" uri="http://127.0.0.1:8281/payment/order/764cc8b5-e612-47e1-818b-225cb35b0c3f" xmlns="http://example.org/state-machine"/> </order>

5.5. Recuperando la lista de pedidos pendientes.

Estamos a punto de finalizar las implementaciones que tienen que ver con las

interacciones entre el cliente y el back-end de Starbucks OMS. Los clientes ya pueden

realizar el pedido de una bebida, revisarlo, actualizarlo y también realizar los pagos,

por lo que ahora ha llegado el momento de implementar las interacciones entre el

barista y el OMS. La primera interacción que vamos a implementar es la lista de

pedidos pendientes. El web service OMS provee una operación llamada getOrders

para permitir este caso de uso. En la solución original diseñada por Jim Webber, el

barista debe ser capaz de acceder a la lista de pedidos en formato Atom feed20 en

tiempo real. Entonces en nuestro caso vamos a configurar el ESB para que nuestra

API manipule el mensaje y realice la transformación desde SOAP a Atom.

Empezamos definiendo la API, que llamaremos StarbucksOrderListAPI. Esta API esta

enlazada con el contexto “/orders”, esta API consiste en un único resource que maneja

las peticiones GET. <api name="StarbucksOrderListAPI" context="/orders"> <resource methods="GET" faultSequence="StarbucksFault"> […] </resource> </api>

El resource simplemente contactará con el servicio OMS del back-end para recuperar

la lista de pedidos pendientes en formato SOAP, entonces en la secuencia out- 20 http://tools.ietf.org/html/rfc4287 y http://tools.ietf.org/html/rfc5023

Page 28: Chakray howto get cup of coffee the wso2 way español

28

Por Juanjo Hernández IT Consultant

sequence aplicamos una transformación XSLT para convertir la respuesta SOAP en

un formato Atom válido.

<xslt key="OrderFeedGenerator"> <property name="SystemDate" expression='get-property("SYSTEM_DATE", "yyyy-MM-dd'T'hh:mm:ss'Z'")'/> <property name="SystemURL" expression="$ctx:STARBUCKS_SYSTEM_URL"/> </xslt>

No obstante, cambiar el formato del mensaje no es suficiente. A no ser que enviemos

una cabecera content-type adecuada con la respuesta, el cliente que ha realizado la

llamada no recocerá la respuesta como una respuesta correcta de tipo Atom feed, por

lo tanto tenemos que añadir el siguiente mediador property a la configuración que

supervisará que la respuesta devuelta tenga el content type “application/atom+xml”.

<property name="ContentType" value="application/atom+xml" scope="axis2"/>

Ahora probamos la api con el siguiente commando Curl

curl -v http://localhost:8281/orders

Si con anterioridad se han enviado nuevos pedidos al sistema OMS mediante la API

StarbucksOrderAPI, ahora deberíamos recibir una respuesta de nuestro Atom feed de

pedidos similar a la siguiente. Advertir que si se realiza la consulta en algunos

navegadores como Internet Explorer que llevan incorporados lectores Atom, la

visualización de la respuesta será formateada para una visualización más agradable.

Page 29: Chakray howto get cup of coffee the wso2 way español

29

Por Juanjo Hernández IT Consultant

Ilustración 9. Internet Explorer con lector Atom.

5.6. Revisando el estado del pago.

Antes de que el Barista pueda entregar la bebida, debe supervisar si el cliente ha

pagado por ella. Nuestra API StarbucksPaymentAPI ya permite esto, si la aplicación

de Barista conoce el identificador del pedido puede revisar el estado del pago del

pedido enviando una solicitud HTTP GET que corresponde al resource del pago.

curl -v http://localhost:8281/payment/order/order-id

La orden superior devuelve una respuesta 200 OK conjuntamente con la descripción

del pago si el cliente ha realizado el pago, en caso contrario el estado devuelto será un

404 Not Found

5.7. Eliminando pedidos completados de la lista.

La Aplicación de Barista debe eliminar los pedidos preparados de la lista de pedidos

pendientes, para que el mismo pedido no pueda ser procesado más de una vez. El

back-end de Starbucks posee una operación removeOrder que puede ser usada para

implementar este escenario. En un entorno RESTful, la manera apropiada de realizar

la acción de borrar un recurso es enviado una petición HTTP DELETE, entonces

definimos el siguiente resource en la API StarbucksBaristaAPI.

Page 30: Chakray howto get cup of coffee the wso2 way español

30

Por Juanjo Hernández IT Consultant

<resource uri-template="/order/{orderId}" methods="PUT DELETE">

Este resource aceptará las peticiones DELETE, invocará la operación removeOrder

del OMS y eliminará el pedido especificado de la lista. Observar el uso de la plantilla

URI “/orders/{orderId}”. De esta forma la aplicación barista puede invocar el mismo

resource especificando diferentes identificadores de pedidos. En la in-sequence del

resource construimos un mensaje que la operación removeOrder SOAP entienda

usando el valor de la variable orderId de la plantilla.

Para probar esta acción puedes ejecutar el siguiente comando Curl. Cómo en todos

los ejemplos anteriores se debe sustituir la cadena order-id por el identificador real del

pedido. curl -v -X DELETE http://localhost:8281/barista/order/order-id

La respuesta debería ser similar a la siguiente: HTTP/1.1 200 OK Content-Type: application/xml; charset=UTF-8 Server: WSO2 Carbon Server Date: Wed, 15 Aug 2012 13:38:20 GMT Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <message xmlns="http://starbucks.example.org">Order deleted</message>

Para asegurar que el pedido ha sido eliminado de la lista, podemos enviar una petición

GET a la API StarbucksOrderListAPI y comprobar en la lista de pedidos pendientes

que es devuelta en formato Atom feed, que ya no se encuentra el pedido eliminado.

6. Mejorando la Solución en general.

Hasta el momento tenemos en las manos una solución prácticamente completa.

Ambos flujos (workflows) descritos en el artículo de Jim Webber han sido

implementados satisfactoriamente. Pese a todo existen multitud de mejoras a hacer.

En esta sección vamos a echar un vistazo a cómo ciertos requisitos no funcionales

como la seguridad, la usabilidad o el rendimiento que pueden ser incorporados a la

solución tan solo con ser implementados sobre el ESB.

Page 31: Chakray howto get cup of coffee the wso2 way español

31

Por Juanjo Hernández IT Consultant

6.1. Negociando el formato del contenido (Content Negociation).

Content Negociation es el mecanismo por el cual un cliente y un servidor se

comunican uno con otro y deciden un formato de contenido a usar para la

transferencia de datos. En nuestra solución hasta el momento, hemos utilizado XML

(application/xml) como el principal medio de transmisión de datos. Sin embargo

podríamos utilizar otros formatos para la transferencia de contenidos, como texto plano

o JSON para lograr el mismo resultado y adaptarse a cualquier dispositivo.

Las aplicaciones cliente en el mundo real tienen sus propios content types preferidos.

Por ejemplo un navegador web normalmente prefiere recibir la información en HTML.

Una aplicación de escritorio basada en Java21 habitualmente prefiere POX, en cambio

un app móvil usualmente preferirá JSON. Para mantener la interoperabilidad, las

aplicaciones servidor (server side) deberían estar preparadas para servir el contenido

usando cualquiera de esos formatos. Con el uso del mecanismo de negociación de

contenidos (Content Negociation) el cliente puede indicar su preferencia de tipo de

contenido al servidor y el servidor puede servir las peticiones usando el Content Type

del cliente.

La especificación HTTP proporciona los elementos básicos para construir poderosos

frameworks de content negotiation. Un cliente HTTP puede indicar las preferencias de

su content type enviando en el mensaje una cabecera Accept en las peticiones. El

cliente puede indicar cero, uno o más tipos de contenidos aceptados. Cuando no se

especifica el tipo de contenido preferido, el servidor de manera predeterminada, usa

uno de los tipos de contenido admitidos.

Vamos a ver cómo podemos añadir una negociación de contenidos básica en nuestra

solución. En este ejemplo no vamos a pararnos en las preferencias enviadas por el

cliente, más bien vamos a definir nuestro propio orden de prioridad para el manejo de

múltiples preferencias. Usaremos el API StarbucksOrderListAPI como conejillo de

indias. Primero necesitamos recuperar el valor de la cabecera Accept enviada por el

cliente, hacemos esto con el siguiente mediador property en la in-sequence como

sigue:

21 http://www.java.com/en/

Page 32: Chakray howto get cup of coffee the wso2 way español

32

Por Juanjo Hernández IT Consultant

<property name="STARBUCKS_ACCEPT" expression="$trp:Accept"/>

Ahora en la out-sequence haremos algunas evaluaciones para determinar qué tipo de

content type se usa para enviar la respuesta:

<switch source="$ctx:STARBUCKS_ACCEPT"> <case regex=".*atom.*"> […] </case> <case regex=".*text/html.*"> […] </case> <case regex=".*json.*"> […] </case> <case regex=".*application/xml.*"> […] </case> <default> […] </default> </switch>

La configuración anterior determina la siguiente orden de prioridad de los tipos de

contenidos:

1. Atom (también usado por defecto)

2. HTML

3. JSON

4. POX

Para probar la negociación de contenidos debemos añadir en nuestros comandos Curl

el contenido aceptado por el cliente y por lo tanto cómo queremos recibir la respuesta

tal como sigue:

curl -v http://localhost:8281/orders curl -v -H "Accept: application/xml" http://localhost:8281/orders curl -v -H "Accept: application/json" http://localhost:8281/orders curl -v -H "Accept: text/html" http://localhost:8281/orders

6.2. Aplicando Seguridad al API

Hasta el momento nuestra API StarbucksPaymentAPI está expuesta sobre HTTP sin

ninguna forma de autenticación, pero eso no es como se diseñan los sistemas de pago

en el mundo real. Debemos restringir el acceso a esta API usando HTTPS e

idealmente debemos introducir alguna forma de autenticación en la ecuación.

Page 33: Chakray howto get cup of coffee the wso2 way español

33

Por Juanjo Hernández IT Consultant

Restringir la API de pago usando el protocolo HTTPS es sencillo. Simplemente se

debe añadir el protocol=”https”22 en la definición del resource, e inmediatamente el

resource estará accesible sobre HTTPS, de la siguiente manera:

<resource uri-template="/order/{orderId}" methods="GET PUT" faultSequence="StarbucksFault" protocol="https">

Ahora cuando accedemos con la siguiente orden Curl a la API de pago usando el

protocolo HTTP:

curl -v -X PUT-d @payment.xml -H "Content-type: application/xml" http://localhost:8281/payment/order/order-id

El mensaje no será enviado ni siquiera al resource. Será remitido a la secuencia

principal del ESB la cual está configurada para devolver una respuesta 403,

obtendremos algo similar a:

HTTP/1.1 403 Forbidden Content-Type: application/xml; charset=UTF-8 Host: 127.0.0.1:8281 Date: Wed, 15 Aug 2012 14:18:28 GMT Server: Synapse-HttpComponents-NIO Transfer-Encoding: chunked Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <error xmlns="http://ws.apache.org/ns/synapse">Invalid request</error>

El único modo de poder acceder ahora a la API StarbucksPaymentAPI es vía HTTPS.

Invocando el siguiente comando Curl como sigue, y obtendremos una respuesta 201.

curl -v -X PUT -d @payment.xml -H "Content-type: application/xml" -k -X PUT https://localhost:8244/payment/order/order-id

Ahora que ya tenemos algo de seguridad a nivel de transporte implementado en

nuestra API de pago, vamos a ver como añadir lógica de autenticación a la solución.

Las APIs REST en WSO2 ESB permiten un concepto llamado handler. Uno o más

handler pueden participar en una API donde interceptan los flujos de mensajes y

añadir funcionalidades de QoS (Calidad de servicio). Para el propósito de este artículo

22 Existe un inconveniente si se realiza esta acción directamente desde el editor de la API de la consola de Administración, si se introduce protocol=”https” al resource y se guarda, la acción se realiza correctamente, pero al volver a abrir el editor manual de la API la palabra https se sustituye por un 2, es decir protocol=”2”, lo cual lanza un error al intentar guardar.

Page 34: Chakray howto get cup of coffee the wso2 way español

34

Por Juanjo Hernández IT Consultant

vamos a usar un handler personalizado que proporciona la funcionalidad de HTTP

Basic Authentication.

Apagamos el servidor de WSO2 ESB si está arrancado. Descargaremos el jar WSO2-

REST-BasicAuth-Handler-1.0-SNAPSHOT.jar23 que implementa la autenticación

anteriormente mencionada y lo copiamos en el directorio repository/components/lib,

posteriormente añadimos la definición del handler en la API de pagos

StarbucksPaymentAPI:

<handlers> <handler class="org.wso2.rest.BasicAuthHandler"/> </handlers>

Cuando reiniciamos el ESB, la API StarbucksPaymentAPI ya estará asegurada con la

HTTP Basic Authentication. Si intentamos acceder como anteriormente el resultado

será una respuesta con estado HTTP 401 Unauthorized, con un mensaje similar al

siguiente:

HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="WSO2 ESB" Date: Wed, 15 Aug 2012 14:35:25 GMT Server: Synapse-HttpComponents-NIO Transfer-Encoding: chunked

Para que la API fuera accesible se deberían pasar las credenciales al comando Curl

de la siguiente manera (usuario: admin, contraseña: admin):

curl -v -k -H "Authorization: Basic YWRtaW46YWRtaW4=" https://localhost:8244/payment/order/order-id

Otra prueba que podemos intentar para comprobar la autenticación es acceder a la

API mediante un navegador web. El navegador mostrará un dialogo estándar de

autenticación para que se puedan introducir las credenciales:

23 https://www.dropbox.com/s/1n57ta3pz0xkamz/WSO2-REST-BasicAuth-Handler-1.0-SNAPSHOT.jar

Page 35: Chakray howto get cup of coffee the wso2 way español

35

Por Juanjo Hernández IT Consultant

Ilustración 10. Dialogo estándar de autenticación en el navegador.

Existen otras maneras de habilitar autenticación en una API o Proxy Service en el ESB

sin usar la propiedad handler, en algunos casos es posible habilitar la autenticación

con mediadores property de alguna forma similar a la siguiente:

<property xmlns:sb=http://www.starbucks.com name="OB_USR" expression="//sb:Starbucks/*[1]/usr" type="STRING"/> <property xmlns:ob=http://www.openbravo.com name="OB_PWD" expression="//sb:Starbucks/*[1]/pwd" type="STRING"/> <property name="OB_CHAR1" value=":" type="STRING"/> <property name="OB_B64CREDENTIALS" expression="fn:base64Encode(concat($ctx:OB_USR, $ctx:OB_CHAR1,$ctx:OB_PWD))"/> <property name="Authorization" expression="fn:concat('Basic',$ctx:OB_B64CREDENTIALS)" scope="transport"/>

Es el mismo mediador el que gestiona la autenticación y un mediador property llamado

Authorization se encarga de la autenticación del mensaje en el servidor.

6.3. Mejorando el rendimiento (Caching).

El tiempo de respuesta en algunas llamadas a la API puede ser significativamente

mejorada si se introduce alguna característica de cacheado en nuestra solución. Jim

Webber en su artículo ya sugiere que la lista de pedidos pendientes debería estar

cacheado para que la generación del feed Atom no sobrecargue los servidores del

Page 36: Chakray howto get cup of coffee the wso2 way español

36

Por Juanjo Hernández IT Consultant

back-end OMS. Podemos implementar esto en WSO2 ESB usando el mediador cache.

El mediador cache almacena las respuestas en una cache de memoria con la clave de

la lista de llamadas DOM. Así mismo si la misma llamada es enviada varias veces,

solo la primera invocación será mediada por el servicio del back-end. Todas las

llamadas subsiguientes serán servidas por la caché. El siguiente ejemplo muestra

como el mediador cache puede ser configurado en una de las secuencias del ESB:

<cache timeout="20" scope="per-host" collector="false" hashGenerator="org.wso2.caching.digest.DOMHASHGenerator"> <implementation type="memory" maxSize="100"/> </cache>

El tiempo de respuestas a cachear y el tiempo de duración de la misma es

configurable en la sentencia anterior con los parámetros maxSize y timeout.

7. Ejecución de la Solución.

7.1. Clientes GUI.

Ahora que la integración está completa, podemos trabajar con algunas aplicaciones UI

que consumen las API REST, estas aplicaciones en el mundo real podrían ser:

• Website.

• Aplicación de escritorio “standalone”.

• Aplicación móvil.

En este punto podemos descargarnos la aplicación starbucks-rest-sample.ja24r y la

ejecutamos con la orden java –jar Starbucks-rest-sample.jar podremos probar todo lo

que aparece en este artículo de una manera gráfica:

24 https://svn.wso2.org/repos/wso2/people/hiranya/rest-sample/bin/starbucks-rest-sample.jar

Page 37: Chakray howto get cup of coffee the wso2 way español

37

Por Juanjo Hernández IT Consultant

Ilustración 11. Aplicación Starbucks Cliente.

Ilustración 12. Aplicación Starbucks Barista.

Page 38: Chakray howto get cup of coffee the wso2 way español

38

Por Juanjo Hernández IT Consultant

8. Problemas encontrados en la implementación original.

Al realizar el ejemplo del artículo orginal de Mr. Hiranya Jayathilaka, encontramos

algunos problemas que ya hemos ido comentando a lo largo del presente documento,

hay otras que no he tenido oportunidad de comentar pero que es interesante dejarlo

aquí explicado con el fin de no perder tiempo en estos detalles:

• El importe de las bebidas se manipula con un doble y se manipula en los

clientes con Formatter, pues bien este Formatter usa como sistema de

puntuación decimal el punto, cómo es habitual en el mundo anglosajón, en

cambio, cómo sabemos, la separación decimal en el mundo latino es la coma,

se debe revisar pues los clientes GUI para que realicen la manipulación

correctamente. Para adaptarlo a cada país concreto debes conocer cuáles son

los países que utilizan el punto y cuales la coma para separar los decimales25

• El tag handler para realizar la autenticación tal y como se comenta en el

capítulo correspondiente “desaparece” al editar la API, aunque si se edita la

API directamente en su fichero XML el ESB lo gestiona y funciona como es

esperado.

9. Conclusiones.

• Es evidente que durante la creación de una completa solución usando el stack

de WSO2, hemos aprendido cosas importantes como REST, API, SOAP,

HATEOAS y el uso de WSO2 ESB para abordar este tipo de solución.

• En la vida real, el empleo de WSO2 ESB deja abierta la posibilidad de mejorar

la solución en todos los niveles: rendimiento, escalabilidad y seguridad.

• Se ven posibilidad de mejora importante conforme se va conociendo la

tecnología, en los siguientes documentos incluiremos mejoras como:

o Uso de WSO2 Business Activity Monitor.

o Seguridad usando WSO2 Identity Server.

o Uso de WSO2 API Manager para gestionar nuestra API.

o Desarrollo de una nueva Aplicación Cliente Mobile (responsive design).

25 http://es.wikipedia.org/wiki/Separador_decimal

Page 39: Chakray howto get cup of coffee the wso2 way español

39

Por Juanjo Hernández IT Consultant

A. Referencias y recursos

• WSO2 AS: http://wso2.com/products/application-server/

• WSO2 ESB: http://wso2.com/products/enterprise-service-bus/

• Artículo “How to GET a Cup of Coffee” de Jim Webber:

http://www.infoq.com/articles/webber-rest-workflow/

• Jim Webber Blog: http://jimwebber.org/

• Artículo “How to GET a Cup of Coffee the WSO2 Way” de Hiranya Jayathilaka:

http://wso2.com/library/articles/2012/09/get-cup-coffee-wso2-way/

• Recursos actualizados para desplegar y ejecutar este ejemplo:

o Archivos configuración API:

https://www.dropbox.com/sh/7el21wipkf6fvne/uxJ5NhY5Ec

o Archivos configuración endpoints:

https://www.dropbox.com/sh/ldlq6rsweb7z7yt/K8OA4GuY9E

o Archivos configuración local-entries:

https://www.dropbox.com/sh/qdoednc843aulzz/hK__izxkng

o Archivos configuración sequences:

https://www.dropbox.com/sh/mszkhj06gn4206b/KQ3VMBfVID

o Archivo jar para Basic Authentication:

o https://www.dropbox.com/s/1n57ta3pz0xkamz/WSO2-REST-BasicAuth-

Handler-1.0-SNAPSHOT.jar

o Archivo aar para creación servicios SOAP OMS Starbucks:

o https://www.dropbox.com/s/b3leesblvkm2eyg/StarbucksOutletService.aar

B. Tabla de imágenes

Ilustración 1. REST TO SOAP Mediación ESB .............................................................. 6

Ilustración 2. Transformación de mensajes REST con ESB .......................................... 6

Ilustración 3. Configuración de contextos y plantillas de URL en resource. ................... 8

Ilustración 4. Solución de arquitectura de alto nivel. .................................................... 13

Page 40: Chakray howto get cup of coffee the wso2 way español

40

Por Juanjo Hernández IT Consultant

Ilustración 5. Solución de arquitectura con ESB. ......................................................... 14

Ilustración 6. Añadir Servicios Starbucks back-end en WSO2 AS. .............................. 15

Ilustración 7. Lista de servicios desplegados. .............................................................. 16

Ilustración 8. Detalle del servicio Starbucks OMS desplegado. ................................... 16

Ilustración 9. Internet Explorer con lector Atom. ........................................................... 29

Ilustración 10. Dialogo estándar de autenticación en el navegador. ............................ 35

Ilustración 11. Aplicación Starbucks Cliente. ................................................................ 37

Ilustración 12. Aplicación Starbucks Barista. ................................................................ 37

Page 41: Chakray howto get cup of coffee the wso2 way español

41

Por Juanjo Hernández IT Consultant

Autor: Juanjo Hernández IT Consultant LinkedIn: https://www.linkedin.com/in/juanjohernandez Twitter: @JuanjoHC Chakray Consulting S.L. www.chakray.com

Revisado por: Luis Peñarrubia IT Consultant Roger Carhuatocto IT Consultant