En este tutorial vamos a ver una introducción a la versión Standalone de WireMock para poder mockear los servicios a los que se conectan nuestras aplicaciones.
1.Introducción
El desarrollo de aplicaciones basadas en servicios es una realidad desde hace lustros que no hace más que reforzarse con la llegada de los microservicios: de una forma u otra nuetros desarrollos acaban consultando datos a servicios API basados en HTTP (SOAP, REST…). Esto establece unas dependencias que dificultan separar y aislar el desarrollo de cada una de las partes: si un servicio A depende de un servicio B y éste no está terminado de desarrollar, la programación del servicio A se verá afectada negativamente.
Es fundamental contar con algún mecanismo para modelar las interacciones con los servicios a los que nos conectamos, de modo que podamos contar con "mocks" que nos permitan romper momentáneamente la dependencia con la implementación real de esos servicios.
Es algo sencillo que cualquiera puede hacer en casi cualquier plataforma. Es fácil crear en nodeJS o Python un script que levante un servidor HTTP y devuelva los valores que queramos. También lo es en Java, pero pienso que debemos centrarnos en resolver el problema y no en crear nuevos, así que mejor si usamos una herramienta completa y contrastada, en vez de desarrollar la nuestra propia.
Wiremock es un producto bastante completo y en continua evolución. Ya lo usábamos para el desarrollo de test de integración (es muy fácil de usar en Java con su API), pero nunca la había usado como herramienta standalone fuera del código de los tests. La verdad es que me ha sorprendido gratamente por su facilidad de uso y lo rápido que hemos podido implantarla. Espero que este tutorial te anime a probarla.
2. Descarga y arranque de Wiremock standalone
Para descargar la versión standalone podemos ir a los repositorios de Maven y localizar la que deseemos:
http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/
En el caso de este tutorial, la última versión fue la 2.5.1, así que la podemos descargar con nuestro navegador o con un simple wget
wget http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.5.1/wiremock-standalone-2.5.1.jar
Para comenzar a usar Wiremock es muy sencillo: se ejecuta como cualquier JAR de Java, siempre que tengamos Java bien instalado en nuestra máquina:
java -jar wiremock-standalone-2.5.1.jar
Nos saluda con un bonito ascii-banner:
Y además nos indica en el puerto en el que está escuchando. Si tenías otra aplicación escuchando en ese puerto siempre puedes cambiarlo con el parámetro –port:
java -jar wiremock-standalone-2.5.1.jar --port 98080
Puedes encontrar más opciones de configuración de arranque con el parámetro –help:
java -jar wiremock-standalone-2.5.1.jar -help
En la renovada página de documentación de Wiremock puedes encontrar una buena descripción de lo que hace cada parámetro: http://wiremock.org/docs/running-standalone/
3. Mappings y ficheros.
Si has ejecutado Wiremock Standalone como te he indicado anteriormente, podrás observar que se han creado automáticamente dos ficheros en el mismo lugar en el que reside el .jar:
- mappings: contiene ficheros en formato JSON con las combinaciones de request a las que atienda y las responses que tiene que dar.
- _files: contiene los ficheros con el contenido de las responses, y que son referenciados desde los mappings. Es posible no usar un fichero y especificar la respuesta en la configuración pero es algo que, a poco que crezca la respuesta, no te recomiendo.
Entonces configurar las combinaciones de request/response que necesitamos es una tarea muy sencilla. Sigue estos pasos:
3.1. Creamos el mapping:
Vamos al directorio mappings.
Creamos un fichero con extensión JSON y el nombre que nos parezca, como por ejemplo: route.json.
Incluimos el siguiente código:
{ "request": { "method": "GET", "url": "/route" }, "response": { "status": 200, "body": "Hola! Esto no es el servidor real, es Wiremock ;-)" } }
Este código indica a Wiremock que cuando reciba una request de tipo GET en la ruta /route, deberá devolver un HTTP 200 (OK) con el body indicado más abajo. En esta primera prueba no nos hará falta el fichero en el directorio __files.
Ahora arrancamos wiremock, que detectará la nueva ruta que está en un fichero con extensión .json en su directorio de mappings. Para ver el comportamiento vamos a arrancarlo con el parámetro –verbose:
java -jar wiremock-standalone-2.5.1.jar --verbose
Con un navegador (o un wget, curl o telnet) accedermos a http://localhost:8080/route, cumpliendo el request que hemos especificado
Y podemos ver en la consola que todo ha ido bien:
Como he usado Google Chrome para hacer la petición, ha intentado además bajar el "favicon" de la página, y Wiremock, al estar en modo verbose, nos indica que no tiene mapping:
3.2. Fichero de respuesta
Si nuestra response es más extensa, es seguro que querremos especificarla en un fichero separado. Para ello:
- Preparamos un fichero de texto simple con el body de la respuesta. Lo guardamos en el ficero __files con un nombre cualquiera y cualquier extensión, como por ejemplo: route.txt. El contenido puede ser
Hola! Esto no es el servidor real, es Wiremock, y además ¡te respondo desde un fichero! ;-)
- Y vamos a indicar un nuevo mapeo en el directorio mappings, similar al anterior pero indicando que lea la respuesta de un fichero. Se hace cambiando el atributo "body" de la respuesta por "bodyFileName":
{ "request": { "method": "GET", "url": "/routeFile" }, "response": { "status": 200, "bodyFileName": "route.txt" } }
Por defecto va a buscar en el directorio __files el fichero indicado: "route.txt". Sencillo ¿no?
Arrancamos de nuevo e servidor y hacemos una petición HTTP GET a http://localhost:8080/routeFile
Así que ya lo tienes bien fácil para empezar a hacer tu servidor de "mocks" si conoces las entradas y las salidas.
Es posible complicar bastante esta lógica: estableciendo patrones en las request o devolviendo respuestas más complejas. Puedes consultar en estas secciones de la documentación: http://wiremock.org/docs/request-matching/ y http://wiremock.org/docs/stubbing/
4. Modo Proxy para Grabación
Si tu desarrollo se está conectando a un servidor y las respuestas no son triviales (lo habitual realmente), es posible que el trabajo de especificar resquest/responses en el mapping se haga eterno… ¡No te preocupes! Wiremock puede actuar de intermediario entre cliente y servidor, grabando las comunicaciones.
La idea es que Wiremock se sitúa entre el cliente y el servidor, actuando como proxy. Durante esta fase, podemos decir a Wiremock que grabe las peticiones del cliente y las respuesta que le da el servidor a estas peticiones:
- Graba un fichero con la ruta en formato JSON que incluye la request y la response.
- Graba el body de la respuesta en el directorio __files
Posteriormente, si desactivamos en Wiremock la opcion de grabación, y dejamos al cliente apuntando a Wiremock, podremos prescindir del servidor, que es lo que buscábamos…
¿Cómo lo hacemos?
Vamos a ver un ejemplo con nuestro Google Chrome (cliente) y una página Web que devuelve JSON. En este caso usaré: http://date.jsontest.com/
Si escribimos la url http://date.jsontest.com/ en google Chrome, se conecta a este servicio de Internet y nos devuelve una respuesta como la siguiente:
Así tenemos un cliente (Chrome) que se conecta a un servicio (http://date.jsontest.com/) en condiciones normales:
Lo que vamos a hacer es intentar sustituir al servidor (http://date.jsontest.com/) para por ejemplo si queremos trabajar sin tener acceso a Internet:
Para ello interpondremos a Wiremock entre ambos, de modo que Chrome se va a conectar a Wiremock y éste, actuando como Proxy se va a conectar al servidor (http://date.jsontest.com/) y le va a proporcionar a Chrome las respuestas que obtenga, como si fuese transparente.
Mientras se produce la comunicación Wiremock va a ir construyendo los ficheros de mappings y __files automáticamente.
Para ello vamos a arrancar Wiremock indicándole que actúe como proxy y que grabe la comunicación. Le indicaremos que todas las peticiones que reciba, las redirija al servidor http://date.jsontest.com/:
java -jar wiremock-2.5.1-standalone.jar –proxy-all="http://date.jsontest.com/" –record-mappings –verbose
Ahora, en el cliente (Chrome), en vez de acceder a http://date.jsontest.com/ vamos a acceder a la URL de Wiremock:
Podemos ver en la imagen como Google Chrome ha recibido la información como si accediese al servidor realmente.
Vemos en la salida de Wiremock que ha detectado la petición y la ha redirigido al servidor, grabando la respuesta:
Como curiosidad, el servidor ha respondido con la compresión GZIP activa, así que la respuesta que muestra por el log está en este formato y no la podemos interpretar a simple vista. No te preocupes que Wiremock la almacena sin comprimir en __files.
Ahora paramos el servidor (cmd+c o ctrl+c, aunque hay forma administrativa de hacerlo a través de una interfaz REST) y vemos a ver qué ha escrito Wiremock:
Para el Mapping ha creado el fichero "mapping-(root)-fntv3.json":
{ "id" : "e05c2f66-0b0b-335d-aa3f-27151f4da0ae", "request" : { "url" : "/", "method" : "GET" }, "response" : { "status" : 200, "bodyFileName" : "body-(root)-fntv3.json", "headers" : { "Access-Control-Allow-Origin" : "*", "Content-Type" : "application/json; charset=ISO-8859-1", "X-Cloud-Trace-Context" : "10f1b68647af1cce777ec4e108373494;o=1", "Vary" : "Accept-Encoding", "Date" : "Sat, 04 Feb 2017 12:24:39 GMT", "Server" : "Google Frontend", "Cache-Control" : "private" } }, "uuid" : "e05c2f66-0b0b-335d-aa3f-27151f4da0ae" }
Y como se puede leer en el atributo "bodyFileName", en el directorio __files etá el fichero de respuesta que ha devuelto:
{ "time": "12:24:39 PM", "milliseconds_since_epoch": 1486211079402, "date": "02-04-2017" }
Ahora ya estamos en condiciones de desconectarnos del servidor. Paramos Wiremock para que no grabe más y lo levantamos normalmente:
java -jar wiremock-standalone-2.5.1.jar
Estamos en este paso:
Como tenemos la nueva ruta especificada, si hacemos una petición a http://localhost:8080 nos va a response con el JSON que grabamos antes:
Como ves es la respuesta que hemos grabado, y por tanto, siempre nos devuelve la misma hora con los mismos segundos. Ya si queremos trabajar con ese JSON sin conexión al servidor podemos hacerlo.
Existen formas de hacer que esta plantilla de respuesta tenga cierto dinamismo, pero eso lo dejamos para otro tutorial.
5. Conclusiones
En este tutorial hemos visto cómo usar Wiremock en su versión Standalone para poder crear nuestro servidor de respuestas "fake" con muy poco esfuerzo y así poder desarrollar nuestros clientes de servicios sin depender del estado del desarrollo del servidor.
[…] en un tutorial anterior vimos cómo podemos usar Wiremock standalone para poder crear un servidor de mocks de los servicios […]
Se le debe dar algún tipo de permisos especiales a la carpeta __file para que se pueda generar el archivo resultante del Modo Proxy para Grabación? Lo pregunto porque al seguir el tutorial y lanzar la petición a localhost:8080 el resultado que me devuelve es el siguiente:
HTTP ERROR 403
Problem accessing /__files/. Reason:
Forbidden