Ejemplos de proyectos en los que han usado MuleSoft: Roche, Airbus, Red Eléctrica, …
API: una interfaz que muestras a clientes en la cual se expone un servicio que va a consumir
ese cliente.
Tengo una entrada, y lo que necesito para almacenar mi salida es el data type (normalmente
es la salida de tipo jason). En la Api se definen funciones (quiero el número de aviones,…)
Una API podría ser una interfaz (manera en la que construyo una API): se define con un fichero
llamado RAML (lenguaje para crear una API dentro de MuleSoft), Web service (diferentes
operaciones que defino en un fichero que va a permitir comunicarme con el cliente), y un API
proxy (un proxy es una capa intermedia que securiza la info que está viajando desde el
frontEnd al backEnd: pongo una capa a mi código que protege mi API para que nadie pueda
acceder a esa información.
Web service: hay dos tipos: tipo rest y tipo SOAP. Métodos de comunicación que permite a dos
software, personas, bases de datos a intercambiar comunicación.
-RESTful: es más sencillo, va por URL. Hay 4 métodos principales: get, post (inserta
info), put (actualiza) delete (borrar). Da velocidad en la manera que da la solución al cliente.
Wsdl: extensión que se le pone al URL para . Arriba se definen las URL que vamos a usar.
Ejemplo de XML: Defino la estructura persona (por ejemplo persona es un string que tiene
para tantos elementos,…) eso es el data type.
<persona>
<nombre>Nely</nombre>
</edad>
</persona>
Usan el HTTP protocol como frontEnd. Los métodos más usados son get, post delete.
Get: devuelven el actual estado del recurso (resource): devuelve la información que
solicitamos y el output puede devolverlo en tipo json o xml.
Post: se crea un nuevo recurso: hacemos un mensaje inicial y genera toda esa
información que le paso en el backend.
Put: actualiza. El delete y Put se usan pasándole un ID que hace referencia al recurso
especifico.
Patch: cuando le damos al put podemos actualizar toda la información y el patch solo
actualiza parcialmente esa información. Por ejemplo: quiero actualizar el número de cuenta de
la persona pero no el nombre. Paso todo el recurso pero selecciono lo que quiero actualizar.
Ejemplo de RESTful
http://server:port/listAllFlights/4?destination=LAX
listAllFlights es la operación. Los uriparam son los que siguen con la barrita; los que siguen con
una interrogación se llaman query param. Se diferencian en la manera en la que filtran. Los
uriparam hace filtros sobre los recursos: quiero hacer un filtro sobre la lista flights (la
operación). Un query hace filtro sobre la información que a mí me devuelve, no sobre el
recurso. Por ejemplo, hasta 4 solo me va a dar el vuelo 4. Y lo que hay detrás de la
interrogación me va a devolver la información interna de ese recurso. Imaginamos que dentro
del recurso 4 tenemos algo con varios valores, como diferentes destinos. El vuelo 4 puede
tener diferentes destinos (LAX y GP). Esto último sería el queryparam.
Los URIparam son los parámetros que iniciamos inicialmente en la URL por los que filtramos.
Solo filtra recurso.
Los query param son parámetros que tienen un nombre (ID). Ej: quiero que me devuelvan los
listados de aviones donde el destination = LAX. Filtran la información de un recurso.
Un recurso es una clase y cada una tiene su ID. Si filtro por los atributos filtro por queryparam
y si filtro por clase, filtro por uriparam.
Estructura: La lista se engloba en corchetes y las llaves para definir los recursos dentro de esa
lista. Entre un recurso y otro después de la llave ponemos una coma (menos el último recurso)
[
{
“ID”:”3”,
“Nombre1”:”MARÍA”,
“nombre2”:”PEREZ”
},
“ID”:”3”,
“nombre1”:”Isabel”,
“nombre2”:”nuñez”,
Dentro de REST hay una serie de herramientas para hacer llamadas de tipo REST. (Ejemplo
postman).
Dentro de Mule se puede ofrecer al cliente el API manager (diseño inicial) o el runtime. Hay
clientes que no necesitan el APImanager. Usaríamos el módulo del runtime. Si necesita de algo
visual necesitaríamos el modulo del APImanager. La API necesita ser securizada con secured
APIs. Estas requieren autentificación (accederíamos con una contraseña, token, client_id y
client_secret, política oauth,…) Podemos también con protocolos de autenticación, política de
seguridad con el oauth, SAML (tipo token), JWT (política propia que va por token),… hay un
montón.
CONCLUSIÓN: El diseño inicial de una API hay que securizarlo (YA VEREMOS COMO).
Toda llamada HTTP tiene un código de status (se devuelve si ha ido bien, mal, si la contraseña
del usuario es una mierda,…) El status code muestra al cliente como ha ido todo, y
normalmente va en el response (la estructura de respuesta llevará por tanto un status code:
http.status pondríamos).
Si no he picado en concreto por ejemplo el nombre que quiero que me filtre me daría uno de
estos códigos. Si se me cae el sistema me devuelve el 500.
POSTMAN: lo usamos para ver lo que nos devuelve el destino, para testear lo que he hecho
Es la herramienta de RESTful.
Partes:
URL: http://localhost:8081/listAllFlights
Body: Puedo elegir la manera en la que envío mi información. Ejemplo: raw es en formato de
texto. Form-data lo uso cuando sé si mi proveedor me facilita la autenticación de clientes. Me
tendrían que decir el formato. Nosotros usaremos siempre el raw. Introduciremos la info de
nuestro recurso: Este body lo usaremos siempre para put y post (ya que en ellos añado
recursos, para actualizarlos y para que sean usados). Para get por ejemplo NO.
Hay URL que vienen con la palabra api pero no tienen por qué tener api manager (solo la URL).
Meto esta URL en Postman en GET. Si le doy a enviar me sale los recursos que ha metido otro
tio picando. Si ahora elijo POST, le doy a body a raw en formato JSON (porque espero ese
lenguaje) y añadiría el recurso.
Para put y delete siempre tengo que filtrar por algo (añadir / y algo más en el URL) ya que para
actualizar o borrar algo tengo que pasar la info de qué. Para delete como lo que quiero es
borrar un recurso, borro por ID (añadiendo /7 por ejemplo) y no tengo que escribir en el body
lo que me borre en sí.
Cuando en las URL aparece la palabra /console/ es que hay una API de por medio. Si pongo esa
URL en la dirección de un explorer me sale la parte visual. De esa manera no hago que la otra
persona tenga que usar Postman y pueda acceder a una info que quiera recuperar:
Esa consola tiene types: donde vienen definidas las estructuras. En resources están los
métodos. Todo esto se hace por el lenguaje RAML. Con un fichero txt creo un fichero RAML.
Dentro del recurso /flights/{ID} tengo un queryparam para filtrar (ID). Al cliente le paso esta
consola y así no le paso el Postman que no va a entender.
Dentro del padre flights tengo Request donde tengo la descripción, queryparam si quiero,
esquema de seguridad para securizar la API,.. La response posible que tengo picada en RAML
es solo la respuesta 200 (en el ejemplo que estamos viendo).
CONSTRUYENDO APIS:
Management Center:
Anypoint Exchange:
Mule Runtime Engine (mis cajitas, flujos, variables, transformaciones,… todo lo que hago yo).
Runtime services: donde tengo desplegada mi aplicación (la aplicación que he construido con
mis cajas). Puedo hacer por un lado mi api, por otro mi runtime y fusionarlas para hacer por
ejemplo mi consola.
Hybrid cloud: diferentes servicios que te oferta Mule, o pagas por ellos o te los da de gratis
pero solo unos días.
Base URI es donde está contenida mi API. Aparece mi URL que puedo meter en internet.
DESIGN CENTER
Nuestros flujos, Mule los hace en design pero al ser una licencia gratuita no te deja hacer nada.
Asiq lo hacemos en el entorno de sannbox (esto es solo en el cloud de mule).
Cuando le doy a deploy se despliega en el sandbox en la nube. Cuando le doy a run se empieza
a generar en si y ver si la puedo correr en runtime.
RUNTIME:
En él se despliegan las aplicaciones que creamos y el estado bueno en que quedan es el started
Nuestra primera caja (listener) tiene siempre un host (local host o 0.0.0.0) y un port.
VAMOS A VER HOY TODO LO DE LAS CAJITAS, TRANSFORMACIÓN, TAMBIÉN CÓMO SE HACE
POR CÓDIGO (DATAWAY=NO POR CAJITAS), ACCEDER A UNA BASE DE DATOS (DATABASE) Y
CÓMO CREAR VARIABLES QUE GUARDEN NUESTRAS COSITAS
Primero creo una caja con un http listener que pone en marcha mi
aplicación en un host/servidor/URL) y un puerto determinado (dentro de ese servidor tenemos
diferentes puertos, números, y son como agujeros de conexión donde la aplicación puede
estar activa runneando, normalmente se usa el 8081, 8283,… los puertos pueden estar
abiertos o cerrados. El path es lo que sigue a la URL, teniendo mi servidor …cómo puedo
acceder a continuación. Para iniciar la conversación hago un GET (lo establezco en la cajita) de
lo que va a venir, en este caso de lista de vuelo.
Creo otra caja Transform. El payload es la estructura de mis datos (no es el body).
Pongo un nombre (outputEjercicio1), formato (este caso json) y metemos en type un ejemplo
de una estructura, la estructura que queremos que aparezca en la salida. Deploy y run.
Copiamos el enlace en Postman.
(*En la nube cuando añado cajas mule intenta ejecutar lo que vamos haciendo y por eso te va
diciendo los errores pero en anypoint esto no pasa, no está mi desarrollo en tiempo de
ejecución, por eso a veces en mi transform no me genera*).
En el listener abro mi conexión y digo “en tal servidor y puerto está lo que hago”. Después
hago una llamada a un sistema externo (no es mi flujo, algo que yo estoy picando), salgo a la
nube y pido la info que quiero usar como la lista de vuelos. Después creo una transformación
para que la info salga de la manera que yo quiero.
EN ANYPOINT EN VEZ DE EN EL CLOUD:
Pulsamos botón derecho y creamos un proyecto. Se nos crea una carpeta con el burrito donde
está nuestra API en XML.
Carpetitas de la izqda.:
El main resource lo usamos para meter las estructuras de nuestra transformación (por
ejemplo un .jsonexample
La mainwsdl
Cada entorno(cajita) tiene unas propiedades diferentes, un puerto diferente (8081, 8082,…)
por cada entorno y para no tener que estar cambiando continuamente el Port ponemos
${“nombre de la variable que me he creado en un fichero que he creado previamente para
definir todas las variables”}. Así solo diré que me ejecute el fichero init.properties
URL: http / servidor (localhost) / puerto (8081) / base= basepath donde está mi aplicación
(ejer1)
Para crear la cajita arrastro HTTP de la derecha y creo primero un listener que tiene que tener
un host y un port. Después arrastro otro HTTP pero al cuadrito de proceso.
En Anypoint la caja de transform no reconoce la salida de la otra caja como estructura de
entrada. Ahora no, tenemos que meterle a mano la estructura de entrada que viene del friki.
Esta está en un archivo que ella nos da.
Ejercicio 4
Ahora además de la caja listener le añadimos una caja Database. Vamos a acceder a una base
de datos y no a un URL. Para esto necesitamos un driver (solemos usar SQL)
Elijo como operación SELECT por ejemplo y escribimos lo que quiero obtener
El database me devuelve una serie de objetos y estos no están en un formato json. Mule
cuenta con un nodo adicional “object to json” y le digo que me traduzca a jason el objeto.
RAML:
https://raml.org/developers/raml-100-tutorial
Es la pate visual, la parte física. Internamente lo que recoge, analiza,.. es un flujo y eso ya se
hace con las cajas.
Un RAML es básicamente un fichero de texto donde tengo escrito un código. Dentro del RAML
hay cosas básicas que hay que poner siempre en el fichero y con lo que decimos que estamos
haciendo un RAML: Cabecera de toda RAML:
#%RAML 1.0
Title: myAPI
version: v1
Existen dos versiones 1.0 y 0.8, ellos usan el 1.0 pero a medida que se aumentan las versiones
de mule las de RAML van bajando.
¿Qué es RAML?
Sirve para definir APIs con los servicios RESTful. Se definen recursos y dentro de ellos se hacen
llamadas a bases de datos (datatypes): puedo hacer GET de personas, pero la estructura de
persona (edad, altura,…) es el datatype y esto va importado como un fichero aparte en mi API.
Se pueden declarar también esquemas y esquemas de tipos JSON (este cambio lo hace
automáticamente).
RAML tiene internamente accesos a ficheros que pueden estar en .YAML o .JSON.
La identación es muy importante, si me salto un espacio peta todo el fichero, es decir que no
me corrige automáticamente y tengo que ir revisando línea por línea.
Los recursos son objetos que identifican al web service dentro de una URL. La URL era
http/local/flights. Flights era el recurso (va con una barra). Un URIparam se encierra por llaves.
DESIGN CENTER:
En design center creamos un mule specification. Le ponemos un titulo. Se crea donde vamos a
a escribir. Le tenemos que añadir lo primero una base: ejemplo:
baseUri: http://localhost:8081/api
Estructura:
#%RAML 1.0
title: demo1
baseUri: http://localhost:8081/api
/Persona:
/Paciente:
/Medico:
Las responses son las posibles respuestas que me puede devolver el servidor. Quiero meterle
todas las posibles respuestas que me va a dar el bankEnd. Por ejemplo le pongo el 200 para
ese tipo de respuesta que quiero que me dé o el 400:
#%RAML 1.0
title: demo1
baseUri: http://localhost:8081/api
description: api de ejemplo
/Persona:
description: recurso Persona
/Paciente:
get:
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: | detrás de los dos puntos pulso
tabulador y después control 1, le doy a intro para que se me baje
directamente y después otra vez al tabulador en la siguiente línea para
escribir: “…” ESTA BARRA SIEMPRE IRÁ CUANDO LO QUE VOY A METER ES A MANO.
SI LO VOY A IMPORTAR NO LO PONGO
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
Un tío entra en esta consola y le aparece un GET. Si lo pulsa y todo va bien a él le aparece en
pantalla “todo ha ido bien” y no el listado de vuelos. Si lo dejo hasta application/json entonces
sí que le aparecería el listado de vuelos y estaría aceptando todo tipo de respuesta.
Todo lo que vaya después de example es lo que yo copio y pego y que me va a aparecer TAL
CUAL al pulsar en la consola GET. (*Anypoint era capaz en base de un example hacerte un tipo
de esquema*).
Si quiero usar un schema estoy diciéndole, pasándole un fichero donde tengo una estructura,
que lo que devuelva tiene que tener esa estructura. Estoy diciendo que lo que me manden
tiene que cumplir ese esquema de validación si no, no muestro esto. Yo hago un esquema que
valida lo que me va a mandar el cliente.
(*Con clientes NUNCA trabajaré con example porque yo estoy diciendo en ellos lo que quiero
que mande el servicio, y eso no tiene sentido*)
#%RAML 1.0
title: demo1
baseUri: http://localhost:8081/api
description: api de ejemplo
/Persona:
description: recurso Persona
/Paciente:
get: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
post: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
/Medico:
El cliente quiere un get de todos los pacientes pero también que me filtre por DNI. Es decir,
quiero un URIparam (lo que va despues de la barra de pacientes y que sería un numero en la
URL). Para ello pongo:
/Persona:
description: recurso Persona
/Paciente:
/{DNI}:
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
Dependiendo de donde ponga mi get me hará el filtro sobre el recurso o sobre un Uniparam.
#%RAML 1.0
title: demo1
baseUri: http://localhost:8081/api
description: api de ejemplo
/Persona:
description: recurso Persona
/Paciente:
get: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
/{DNI}:
get: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
Puedo poner un get para el listado de los pacientes o sobre el recurso DNI.
Queryparam me sirve para que me filtre además de por DNI por compañía.
TODO ESTO QUE HEMOS HECHO HASTA AQUÍ HAY QUE HACERLOS POR CAJAS
EJERCICIO:
Vamos a hacer:
Un RAML con:
versión 1.
Descripcion
Un único recurso que se va a llamar: log in, este log in va a tener una descripción
Queryparameters: user y password y estos llevarán las propiedades anteriores. El usuario va a
ser requerido y el password no.
Respuestas contempladas: 200 y un mensaje que me diga que todo ha ido perfe. También la
respuesta 400 que me diga que me he equivocado en la respuesta, el 401 y 500 (mirar tabla).
#%RAML 1.0
title: demo1
baseUri: http://localhost:8081/api
description: api de ejemplo
/Persona:
description: recurso Persona
/Paciente:
get: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
queryParameters:
nombre: #es un queryparameter y escribo sus props
displayName: Nombre #como quiero que aparezca en mi consola
type: string
description: nombre del susuario
required: true
example: Nely #con esto le hago ver el campo que tiene que
meter, le aparEcerá el nombre pero él puede cambiarlo por el suyo, esto
es util para por ejemplo la est de fechas
apellido:
displayName: Apellido
type: string
description: apellido del usuario
responses:
200:
body:
pplication/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
/{DNI}:
get: #para extraer datos del paciente uso el método get
#usamos un metodo get para listar todos los pacientes
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
post:
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
put:
responses:
200:
body:
application/json:
example: |
"Todo ha ido bien"
401:
body:
application/json:
example: |
"No autorizado"
/Medico:
En este ejercicio solo estamos haciendo por RAML la parte visual. Normalmente a partir de la
parte visual vamos a hacer el flujo. El cliente por tanto tiene que darlo todo super claro
porque primero haré la parte de diseño y después ya le vamos añadiendo la funcionalidad a
ese diseño. Aquí como no tiene ninguna funcionalidad hecha (no hay un runtime hecho con
sus cajitas) si le doy a get no va a pasar nada.
#%RAML 1.0
version: 1.0
title: holaDemo
baseUri: http://localhost:8081/api
description: API para meter usuario y contraseña
/Login:
description: Meter el usuario y contraseña
get:
queryParameters:
user:
displayName: Introduce tu usuario
type: string
description: nombre del usuario
required: true
example: María #Esto a él le aparece tal cual y así sabe
como tiene que meter su nombre, Él puede cambiarlo
password:
displayName: Password
type: string
description: contraseña asociada al usuario
required: false
example: $$$$$ #Así el usuario ve un ejemplo de como es la
contraseña
responses:
200:
body:
application/json:
example:
{"code return" : "OK"}
400:
body:
application/json:
example:
{"code return" : "Solicitud fallida"}
401:
body:
application/json:
example:
{"code return" : "No autorizado"}
500:
body:
application/json:
example:
{"code return" : "Error en el servidor"}
BUILDING APIs:
Lo importante es el payload, donde está la chicha. Hay otras cosas que me enriquecen el
mensaje, me dan info. Ejemplo un inbound property (que es un queryparam), uriparam,
header, … Para acceder a estar propiedades tenemos que picar código.
Para acceder al queryparam que es el usuario en mi ejemplo anterior tendría que escribir:
message,inboundProperties.'http.query.params'.user
(*Inbound son propiedades de la entrada*)
Si queremos acceder a
message.outboundProperties.xxx
el outbund son propiedades de salida, por ejemplo sería cuando el tío cambia el nombre.
Puede ser modificado durante el flujo, o no.
Message.attachement
APIKitRouter:
Es necesario para mi API, es un nodo dentro de mi flujo. Siempre va detrás del http inicial.
Gracias a este nodo configuro donde quiero que se vaya cuando alguien haga la acción en la
consola. Cuando el tío le da a POST, se ejecuta el nodo POST gracias a esto. Es un
ENROUTADOR.
Todo enroutamiento dentro del APIKit le podemos aplicar una política de seguridad. Es muy
importante por esto, para poder securizar.
Busco en la paleta Flow, arrastro el icono y le cambio el nombre. Añado de la paleta maping
exception estrategy como otro flujo y después un reference exception Strategy dentro del
primer flujo, de manera que cuando haya un error va a venir ahí y eso hará referencia a la caja
de referencia donde los errores estarán mapeados (le saldrá al cliente por pantalla que ha
habido el error por ejemplo 200). Dentro de la caja mapping irán todas nuestras excepciones y
para cada excepción haré otra caja (cogida de la paleta como exception maping). Cada cajita le
pongo un nombre (ejemplo: 401, 400,…).
Mule sabe que son excepciones pero no sabe como tratarlas. Yo le digo que haga uso de un
módulo de Mule añadiendo este enlace en el más verde A CADA CAJA:
org.mule.module.apikit.exception.NotFoundException
ESTO SIEMPRE ES ASÍ.
Cajita401: quiero a conciencia que muestre un mensaje que yo escribo. HAGO siempre esto:
Arrastro de la paleta Property. Y ahí le digo que voy a meter un json como aparece:
Para poder escribir lo que yo quiero arrastrar un Set payload despues de Property y escribo lo
que veo en la anterior pantalla TAL CUAL PARA TODAS LAS CAJAS.
Después en Set Payload escribo en formato json lo que quiero que aparezca tal cual. Escribiría:
[{“code return”:”blablablá”}]
Creo otro flujo que va a ser mi consola. Hago en ambos flujos los HTTP iniciales. El de la
consola se va a hacer como el primero pero en el Path pongo /console/* (el asterisco significa
lo que sigue). En el flujo normal pondría /api/*. Pongo eso porque en mi RAML en baseUri he
puesto: http://localhost:8081/api
En los allowed methods si solo voy a usar un GET o PUT lo escribo, si voy a usar más lo dejo
vacío.
Hago otro flujo debajo de la consola para las variables. Arrastro a la parte process de este flujo
una Variable de la paleta.
Le doy a Set variable, le doy un nombre (usuario) y en el Value pongo lo que va a contener que
es el user de mi RAML y pondría así: #[message.inboundProperties.'http.query.params'.user]
Esto ahora mismo aparecerá vacío y hasta que el tío no escriba algo en la consola no se me
rellena. Si quiero que siempre aparezca lo mismo lo escribiría yo tal cual en la casilla en vez de
lo de antes.
Si ahora quiero que me muestre por pantalla Hola Pepito tengo que arrastrar detrás del flujo
Variable, un Set Payload.
Lo que hicimos para el movil fue subir a RUNTIME pero con el API manager no hicimos nada.
(*Yo ya lo tengo en el cloud (tiene una URL) porque me pude meter desde el movil PERO si lo
quiero securizar tengo que desplegarlo en el API manager. Si el cliente no me lo pide le paso la
URL y punto*).
En una versión: (ejemplo versión 1.0.0) el digito de más a la derecha se aumenta cuando yo
hago algún cambio de código, cuando es un minor change (cuando cambio una tontería). El del
medio es cuando cambio algo más importante pero no la funcionalidad. Por ejemplo le añado
una response más para que muestre por pantalla. El número de la izquierda cambia cuando el
cambio realizado es importante. Esto se llama control de cambios, control de versiones. Uno
sube a un repositorio el cambio del código, si otra persona ha modificado algo también lo sube
y esta tool lo fusiona todo y aclara.
Ahora nos vamos a API manager, y ponemos en el nombre el nombre que le hemos dado antes
en el design manager. Estamos metiendo en mi propio cloud (change) de mule, mi RAML.
Esto tenemos que enlazarlo con mi RUNTIME del otro día para que MULESOFT me haga un
único proyecto nuestra API de ahora con lo de las cajitas del anypoint (programa).
Nuestro .zip lleva el RAML y las cajitas. El RAML y las cajitas los tengo contenidos en el
RUNTIME que me genera una URL. Aquí lo tengo todo PERO la seguridad se aplica solo a la
parte visual porque es lo que es lo que cualquier tío ve fuera.
El API MANAGER lo uso si el cliente pide seguridad (además se usa para estadísticas y eso pero
nosotros sobre todo hacemos la API manager para crear políticas de seguridad).
Cuando en el API MANAGER tengo mi RAML desplegado, esta API pasa a ser la principal de mi
proyecto, ya no la del .zip. Si solo quiero tenerla en mi RUNTIME, como consola como el otro
día, ese .zip es el principal.
Para ello miramos debajo en API configuration, le damos a Endpoint with proxy y lo demás lo
dejamos igual. En advanced options lo dejamos todo igual y clicamos el tick. Le damos a save y
se nos despliega para configurar el proxy.
Se le pone un nombre que es el nombre final que le doy al cliente, no puede ser igual al del .zip
desplegado del RUNTIME. Ponemos la versión del RUNTIME (era 3.8. algo) y le damos a deploy.
Después debe aparecer una barrita que pase de naranja a verde.
Si me voy a RUNTIME ya me aparece (se ha creado un archivo proxy con la palabra Gateway y
si cojo esa URL, copio y pego en un navegador y le añado /console puedo probarla. Ahora toda
modificación que yo haga en mi RAML se me cambiará en la API MANAGER porque ahora esta
es la principal (es la que tiene seguridad).
Si quiero modificar mi RAML, una vez he hecho el cambio, tengo que desplegar por partes otra
vez la API: publicarla en mi echage. Una vez he cambiado lo que sea en mi RAML, le doy a
guardar y a mi símbolo infinitio.
Ahora nos metemos en el API MANAGER, nos metemos en nuestra API. Le damos a action y a
change especification y cambiamos la versión. Proxy sin embargo no tenemos que desplegarla
de nuevo.
SOLO SE REDESPLIEGA EL PROXY CUANDO NUESTRA URL INTERNA (NUESTRO HTTP) HAYA
QUE ASIGANARLA A OTRO PROYECTO O CUANDO NUESTRA URL CAMBIA POR CUALQUIER
MOTIVO. CON CAMBIOS DEL RAML,… NO HACE FALTA, MULE ENLAZA DIRECTAMENTE EL API
MANAGER CON EL RUNTIME.
Buscamos en la lupa y ponemos cmd (command Prompt – java) que es la consola de mi PC.
Aquí podemos llegar a archivos de nuestro pc. Para ir hacia atrás le damos a espacio, cd ..,
intro.
Cuando llegamos a C: pegamos el link de la carpeta que queremos buscar. Después escribo: dir
y me sale el contenido que hay en mi carpeta.
Después pego el archivo.jar de derby (no sé bien qué es).
He creado un flujo con su HTTP listener, un data base (en el que de alguna manera he enlazado
con el del friki de manera rara porque no era por sql y que ella lo ha hecho siguiendo una guía)
y un object to jason (que no tocamos). En el http en el Path tenemos que meter algo como:
/BD.
Creo un segundo flujo que cambio el nombre y cuyo puerto cambio. Dos http LISTENER no
pueden tener mismo puerto, así que le pongo 8082.
Como es un uriparam lo pongo entre llaves. (en la URL pongo el número directamente que
quiero que filtre tras una barra (así lo probaría en Postman)
El uriparam lo metemos en una variable y en el select en vez de poner todo vamos a hacer
referencia a la variable.
Para ello arrastramos de la paleta tras el http una Variable, cuyo valor que le ponemos será:
#[message.inboundProperties.'http.uri.params'.TOAIRPORT] TOAIRPORT es el recurso que el friki le ha
puesto. A esta variable yo le pongo el nombre que quiera, en este caso destination.
DEBUGAR
Debugar es ver lo que está pasando en cada nodo para ver errores posibles.
EJERCICIO CON POST
Hacer una API (tendrá por tanto raml) en el manager y un .zip. La API tendrá un recurso
login, el método será un post, le añadimos a la API toda la información necesaria. En el body
del método post metemos un esquema (en vez de example), este esquema nos lo da ella.
Este esquema no dice nada, solo da la estructura. Quiero que al usuario le salga por pantalla
además un ejemplo de lo que tiene que meter. Viendo ese esquema entenderemos el
ejemplo que le tenemos que decir al jipi que tiene que meter. Este ejemplo tenemos que
incluirlo como .json, lo vamos a incluir y no escribir nosotros mismos.
Respuestas posibles contempladas: 200, donde se presenta el mensaje al cliente, el 400, 401,
405, 415, 406 y 500.
Método, parámetro, body, mediatype, esquema en caso de que lo haya y ejemplo en caso de
que lo haya
SCHEMA VS EJEMPLO
Un esquema es un código el cual sirve para validar un ejemplo que el usuario meta por
pantalla. Dentro del esquema tengo que definir que todo username es un string, que es
requerido y le voy a dar una longitud (un max y un min). ESQUEMA = VALIDACIÓN DE DATOS
DE ENTRADA.
/Login:
post:
body:
application/json:
schema: |
{
"type": "object",
"$schema": "http://json-schema.org/draft-03/schema",
"id": "http://jsonschema.net",
"required": true,
"description": "Authentication Credentials",
"properties": {
"username": {
"type": "string",
"required": true,
"minLength": 4,
"maxLength": 20
},
"password": {
"type": "string",
"required": true,
"minLength": 4,
"maxLength": 30
}
}
}
example: !include complemento/ejemploejerciciopost.json
responses:
400:
body:
application/json:
example: |
{"respuesta" : "Solicitud fallida"}
401:
body:
application/json:
example: |
{"respuesta" : "No autorizado"}
405:
body:
application/json:
example: |
{"respuesta" : "No autorizado"}
415:
body:
application/json:
example: |
{"respuesta" : "Tipo de medio no soportado"}
406:
body:
application/json:
example: |
{"respuesta" : "No aceptable"}
500:
body:
application/json:
example: |
{"respuesta" : "Error en el servidor"}
Para generar los flujos desde el RAML: en el fondo del mismo raml pulsar botón derecho y
generar mule Flow. Hacer los cambios de redirecciones y nombres.
Dentro del RAML vamos a hacer cambios para hacer el código más simple. Para ello vamos
haciendo archivos (files) donde pegamos el esquema, que después en el RAML llamaré (con
!include ….). También las responses las copio y pego y las meto en un nuevo archivo RAML. A
este también haré referencia. (VER DEBAJO).
SUBFLUJOS
Vamos a almacenar en una variable el usuario y dependiendo del valor del usuario hacemos un
if (nodo choice). Si lo que tiene mi usuario es igual a Nely entonces lanzo por consola un
mensaje que diga bienvenida Nely. Si no aparece Nely, quiero que además de que me diga el
mensaje lo siento pero no puedes acceder al login, quiero que el http status code cambie a un
401 y para eso tenemos que setear una propiedad del mensaje.
Para hacer un subflujo, creo un subflujo debajo, lo llamo condicional y le meto todo el choice.
Hago un flowreference dentro del flujo anterior y hago referencia al flujo condicional. Así creo
un subflujo.
DATATYPE
En un get voy a meter un acceso a mi lista de objetos.
type: object
properties:
ID?: integer #es una clave primaria, por eso lleva ?, porque es potencialmente filtrable
code: string
price: number
departureDate: string
origin: string
destination: string
emptySeats: integer
plane:
type: object
required: false
properties:
type: string
totalSeats: integer
Dentro de ese anterior raml es donde tengo el texto de arriba (en ese raml tengo la
cabecera: #%RAML 1.0 DataType para decir que es un datatype, como hicimos con trait).
Hacemos una api con traits con un unico recurso flights y vamos a tener la posibilidad
de filtrar por un uriparam. El recurso flights va a tener un queryparam llamado
destination (va a ser requerido). El destination va a ser una enumeración de datos:
SFO, LAX y CLE. Quiero que vea los distintos tipos de respuesta que nos puede devolver
cada uno de los métodos. El recurso flight va a poder jugar con get y post. En el post
metería un esquema para poder validar que la info que mete el cliente en un vuelo es
correcta. Voy a poder filtrar el uriparam con get, delete y put y quiero que el cliente
vea por pantalla lo que él puede utilizar para usar estos métodos. Para el delete no
hace falta body y para el put sí hace falta body porque para actualizar algo, que es
meter info, tengo que hacer un body.
#%RAML 1.0
title: ejerciciocomplejo
version: v1
baseUri: http://localhost:8081/api
traits:
excepciones: !include traits/exceptionstraits.raml
excepciones2: !include traits/exceptionstrait2.raml
types:
AmericanFlight: !include dataTypes/AmericanFlightDataType.raml
modoesquema: !include schemes/schema.json
/flights:
get:
queryParameters:
destination:
required: true
enum:
- SFO
- LAX
- CLE
body:
application/json:
responses:
200:
body:
application/json:
type: AmericanFlight[]
is: [excepciones2]
post:
body:
application/json:
schema:
type: AmericanFlight
example: !include ejemplos/ejemplo.json
responses:
is: [excepciones]
/{ID}:
get:
body:
application/json:
responses:
200:
body:
application/json:
type: AmericanFlight[]
is: [excepciones2]
put:
body:
application/json:
type: AmericanFlight
example: !include ejemplos/ejemplo.json
responses:
200:
body:
application/json:
example: |
{
"http.status:" : "El vuelo ha sido actualizado con
exito"
}
is: [excepciones2]
delete:
body:
application/json:
responses:
200:
body:
application/json:
example: |
{
"http.status: " : "El vuelo ha sido borrado
correctamente"
}
is: [excepciones2]
Una vez hecho mi raml genero mis flujos. les cambio los nombres, veo que los http están
bien y sus paths.
Ahora enlazo al kit router los flujos que he hecho. (dándole al + verdecito).
Configuro en mi flujo get un http. le doy al + y añado la URL de los datos del cliente. (el
(host, port y Path de su URL). Fuera ya de la configuración del HTTP (del + verdecito)
añado
Todo lo que vaya en mi url lo configuro en el http. Como bath ponemos el recurso
(/flights).
En el recurso get vamos a hacer que al cliente le aparezca por pantalla la lista de vuelos
según lo que haya elegido (LAX, CLE o SFO). Cuando el cliente elige, tengo que coger lo
que ha elegido y almacenarlo en una variable para poder ahora filtrar en la lista de todos
los vuelos.
Para ello arrastro delante de mi HTTP una VARIABLE, que recogerá ese valor (en mi caso
decisióncliente).
En HTTP se FILTRA ASÍ: le damos a Add Parameters, en tipo query, añadimos en el Value
el nombre del query, en este caso destination y el value escribiríamos
#[flowVars.decisionCliente].
traits:
- client-id-required:
queryParameters:
client_id:
type: string
client_secret:
type: string
/products:
get:
is: [client-id-required]
description: Gets a list of all the inventory products.
Lo que hay después de get tengo que ponerlo debajo de todos los gets que tenga en el
Proyecto.
Cambiar también en el raml la baseUri por el URL del zip desplegado (proxy)/api. Le
damos al infinito para publicar.
Nos vamos al APImanager y le cambiamos en la derecha en el botón action en Change
API specification la versión para poner la nueva que se ha creado al haber securizado.
Ahora hemos copiado y pegado el raml del design manager al anypoint (el programita).
Client_id y Client_secret son querys que vamos a meterle a los gets. En el raml no
tenemos que añadirle el query en sí porque en los traits ya están definidos y como en el
is: estamos poniéndole la privacidad pues perfe. En el flujo sin embargo sí vamos a tener
que añadir las conexiones externas client_id y client_secret. Para ello metemos en los
HTTP de los flujos get (ya que he aplicado la privacidad a todos ellos) queryparams con
Name: client_id
Value: #[message.inboundProperties['http.query.params']['client_id']]
Name: client_secret
Value: #[message.inboundProperties['http.query.params']['client_secret']]
Generamos un zip nuevo y ahora al desplegarlo no hace falta redesplegar el proxy
porque no hemos cambiado el URL del RUNTIME.
Este zip lo despliego no en el Gateway sino en el otro (el que es solo.zip). para eso pulso
sobre el archivito.zip y a la derecha le doy a choose file y elijo el nuevo .zip securizado.
Ahora me tengo que ir a API manager y meterme en mi proyecto (dándole a v1). Le doy
a redeploy y se me forma el proxy automáticamente a partir del nuevo.
APUNTES YOUTUBE
COSAS NUEVAS EN EMPRESA
Message Enricher: (las variables que quedan dentro de ese flujo no pueden salir), se acaban
perdiendo. Si me quiero quedar con algo de lo que se da dentro en la salida de este flujo
guardo lo que yo quiero seguir teniendo.
Prerequisites
This document assumes that you are familiar with Mule and its basic concepts.
Using MEL
Based on information Mule extracts from the message or its environment at
runtime, Mule evaluates expressions to complete three types of tasks:
o Extract information that it can use to process the current message; this can be
useful when set inside an expression component or expression transformer:
o #[payload]
o #[message.inboundProperties.'propertyName']
o #[payload.methodCall(parameters)]
o #[xpath3('//root/element1')]
o Evaluate conditions using the contents of the current message; this can be
extremely useful to filter messages from being processed:
o #[payload.age > 21]
o #[message.inboundProperties.'locale' == 'en_us']
o Define a target, other than the message payload, in which to store the result of
an expression evaluation; typically, this is helpful when set inside a message
enricher
o #[flowVars.output]
Mule accepts the expression #[payload] as a shortcut for #[message.payload]. This shortcut only
applies to the payload field.
The following examples illustrate a few ways in which you can use MEL.
10. Use an expression to extract information, then use it to replace a token with an
actual value. For example, a logger can extract information from the payload
contents and place it into a logging message, as shown below.
If the payload is an object and you can call a method to extract information, the
expression to extract may appear as follows.
Expressions in Mule
It’s important to know that MEL has not always been the de facto expression
language Mule uses. Prior to version 3.3.0, expressions in Mule varied in syntax
according to their specific evaluator. Thus, although these expressions
supported a wide variety of functionality, the variation in syntax rules was time-
consuming to learn. This older style of expression was written in the
format: #[evaluator:expression]. A colon separated the evaluator from the
expression itself.
Learning MEL
If you’re already familiar with Java, learning MEL is not difficult. That said, it’s
important to comprehend some Mule-specific details before you learn how to
apply MEL expressions in your application.
1. Understand the Mule message structure. Because you use MEL to act upon
the contents of a Mule message object (payload, properties and variables), you
first need to understand the basic structure of the message. If you are not
already familiar with it, read about the Mule message structure.
2. Understand how to see the contents of the Mule message. To be able to act
upon it, you need to be able to figure out what type of data the message
contains. Is the payload an array? Does the message contain a flow variable?
What inbound properties exist? The Mule Message Tutorialdescribes the tools
you can use to see inside the message, so that you know how to use MEL
expressions to manipulate the data.
After having absorbed this material, you are ready to begin learning about MEL
basic syntax, and start using expressions in your application.
ELEMENTOS DE MULESOFT
https://docs.mulesoft.com/mule-runtime/3.8/anypoint-
connectors
https://docs.mulesoft.com/mule-runtime/3.8/scopes
https://docs.mulesoft.com/mule-runtime/3.8/components
https://docs.mulesoft.com/mule-runtime/3.8/transformers
https://docs.mulesoft.com/mule-runtime/3.8/filters
https://docs.mulesoft.com/mule-runtime/3.8/routers
https://docs.mulesoft.com/mule-runtime/3.8/error-handling
https://docs.mulesoft.com/mule-runtime/3.8/anypoint-
enterprise-security
https://docs.mulesoft.com/mule-runtime/3.8/cache-scope
https://docs.mulesoft.com/mule-runtime/3.8/foreach
https://docs.mulesoft.com/mule-runtime/3.8/flow-reference-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/groovy-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/java-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/javascript-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/python-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/ruby-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/script-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/rest-component-reference
https://docs.mulesoft.com/mule-runtime/3.8/cxf-component-reference
Script Transformers
https://docs.mulesoft.com/mule-runtime/3.8/script-transformer-reference
https://docs.mulesoft.com/mule-runtime/3.8/append-string-transformer-reference
https://docs.mulesoft.com/mule-runtime/3.8/expression-transformer-reference
https://docs.mulesoft.com/mule-runtime/3.8/xslt-transformer-reference
SAP Transformers
https://docs.mulesoft.com/mule-runtime/3.8/sap-connector
https://docs.mulesoft.com/mule-runtime/3.8/property-transformer-reference
https://docs.mulesoft.com/mule-runtime/3.8/variable-transformer-referenceç
https://docs.mulesoft.com/mule-runtime/3.8/session-variable-transformer-reference
https://docs.mulesoft.com/mule-runtime/3.8/filters
https://docs.mulesoft.com/mule-runtime/3.8/choice-flow-control-reference
ETC…