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.
41
Embed
Chakray howto get cup of coffee the wso2 way español
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
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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.
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
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/
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.
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/
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
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
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" />
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/
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
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
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
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
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
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
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">
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
27
Por Juanjo Hernández IT Consultant
Si todo va bien, se debe recibir un estado HTTP 200 confirmando la actualización del
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
28
Por Juanjo Hernández IT Consultant
sequence aplicamos una transformación XSLT para convertir la respuesta SOAP en
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.
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
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.
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