Una vez terminado mi trabajo para la wiki 2.0 (estuve trabajando en la parte de migración que consistía en migrar las bases de datos de otras wikis como Ewiki o la antigua Nwiki hacia la nueva wiki), ahora he sido redirigido a la última parte del proyecto de final de carrera: Ayudar en el desarrollo de la capa de Interoperabilidad para Moodle 2.0 (más conocido como Web Services).
Cada vez más usuarios y organizaciones utilizan Moodle, y estos cada vez utilizan otras plataformas de acceso, ya sea un móvil, cómo una wii, un iPhone... Esta capa garantizará independencia tecnológica que permitirá a estos dispositivos "hablar" con Moodle, "interoperar". Antes Moodle era una aplicación monolítica y todo funcionaba desde la propia aplicación Moodle.
Esto puede derivar en un amplio abanico de posibilidades: Los desarrolladores podrán crear clientes que puedan interactuar con Moodle.
Ejemplo:
- Moodle está hecho en PHP, y el Web Service estará implementado de la misma forma. Y tenemos a la FIB, una facultad que tiene Moodle instalado para sus estudiantes, y (por decir algo) una aplicación de automatrícula hecha en Python, y desearía que, a la vez que se matriculan los estudiantes, se cree un usuario automáticamente, sin necesitar que haya un becario que haga el trabajo de ir creando a los estudiantes en el Moodle uno a uno.
- De forma "directa", no puedes hacer que una aplicación escrita en Python se comunique con otra aplicación escrita en PHP. Sin webservices, nuestro objetivo es difícil de conseguir.
- Con Web Services podemos conseguirlo. Imaginemos que Moodle dispone de un servicio que es "crear usuario". La aplicación en Python utilizaría ese servicio (transmitiéndole los datos necesarios), y Moodle le contestaría a la aplicación diciéndole si ha habido éxito en la inserción o no, y posibles errores.
Y todo eso, cómo se hace?
Hay varios tipos de protocolos que permiten esto: REST, SOAP, OKI, XML-RPC... De momento, sólamente hay implementado parcialmente REST y SOAP. Estos són los encargados de comunicarse con los clientes. Los clientes mandan la petición en un formato estándar (ya sea en una petición HTTP como en REST, o una petición HTTP + un XML como en SOAP), y el Web Service contesta con un XML con los resultados.
Aquí pongo un esquema de lo que sería la comunicación:
Una vez realizada esta pequeña introducción a los Web Services, pasemos otra vez a Moodle y el trabajo que hay que desarrollar.
En esta capa de Interoperabilidad habrá protocolos REST, SOAP, OKI... cada uno de estos componentes invocará las operaciones de dominio y devolverá resultados. Las operaciones de dominio, por supuesto, serán comunes (se hace una implementación única para todos los protocolos). Estas operaciones que se ponen a disposición del Web Service se conoce como API (application programming interface, un conjunto de operaciones o rutinas que sirven para soportar el desarrollo de aplicaciones).
En este dibujo mostramos cuál será la estructura interna de los WebServices:
- Estará compuesto por tres capas:
- la Externa, la Media y la Core. En la externa (ubicada en la carpeta /webservices) se encontrarán los protocolos (REST en /webservices/rest, SOAP en /webservices/soap,...). Esta capa tiene por objetivo analizar la petición del cliente, y llamar la función correspondiente del external.php
- La capa media está compuesta por varios fichero external.php, un fichero external.php por cada parte de la aplicación (/admin/external.php, /user/external.php, /mod/forum/external.php,...). Estos ficheros se encargan de tratar los parámetros que le llegan de la capa externa y pasarselos a la capa de core.
- La capa core está compuesta por ficheros api.php, un fichero por cada parte de la aplicación, como en el caso del external.php. Estos ficheros son lo que sería la antigua lib.php, el fichero donde se implementan las funciones para acceder a base de datos o ejecutar diferentes acciones.
Cómo implementaremos esto?
El siguiente esquema explica cual será el funcionamiento básico de una petición:
- El protocolo no guarda estado. Esto significa que en cada petición el cliente deberá autentificarse enviando su usuario y su password. Una vez autentificado, el protocolo devolverá un "token", que autentificará al cliente durante toda la petición.
- El cliente llama una función concreta del Web Service, enviando el nombre del módulo, función a llamar y parámetros, incluído el token.
- El protocolo utiliza el token para verificar que la sesión es válida y activa.
- El protocolo llama a la función externa correspondiente, ubicado en el external.php del módulo correspondiente.
- La función en external.php comprueba que el usuario realmente está autorizado a realizar dicha acción.
- La función externa llama a la correspondiente función en core.
- Y el resultado de la función es devuelto al externo, de externo al protocolo, y del protocolo al cliente./li>
Aquí tenemos el diagrama de secuencia que correspondría al ciclo de una petición (almenos en REST, y supongo que será un esquema compartido por todos los protocolos):
La solución de la implementación para el caso de la capa media y de core (la implementación de la capa de protocolo porque depende del protocolo) es la siguiente:
- external.php:
Se usa una convención de nombres para el nombre de las clases: las clases tendrán la terminación "_external", y delante llevarán el nombre del módulo en cuestión. Si se trata de una clase de core (como admin o user) el nombre de la clase sería admin_external o user_external respectivamente, y si es un módulo (como el foro) entonces seria mod_forum_external. Básicamente el nombre depende del Path: por ejemplo, como el external.php del foro se encuentra en /mod/forum, la clase debe llamarse mod_forum_external. Si cambiáramos el nombre de la carpeta, habría que adaptar el nombre de la clase.
Todo esto es por temas de implementación interna. Recordemos que habíamos dicho anteriormente que la capa de protocolo es la que se encarga de localizar y delegar la petición al external.php correspondiente. Pues la localización del módulo se realiza mediante esta convención de nombres.
- En la constructora de la clase se definen las operaciones que se deben llamar en una array "descriptions". Por cada operación se definen cuales son los parámetros de entra y de retorno.
- Las operaciones que se definen en la clase serán todas estáticas, y comprobarán la autorización del usuario, adaptarán los parámetros y llamarán a la función correspondiente de core.
- api.php:
- Todas las funciones serán estaticas.
- El nombre de la clase seguirá la misma convención de nombres que en el caso de la external, pero finalizado en "_api".
En esta página podréis ver código de ejemplo del protocolo REST y del external.php: http://docs.moodle.org/en/Development:Web_services
Enlaces relacionados:
Vaya... hacía mucho que no visitaba tu blog; veo que lo has cambiado: ahora leo en castellano xD y la plantilla también es nueva...me gusta más ésta ;)
Bueno...únicamente quería dejarte por aquí un mensajito de amor ^^ que no sé si estarás ocupado ahora pero vamos que yo estoy estudiando, es por eso que prefiero no llamarte xD.
Pues na, mi vida... que una canción me ha hecho acordarme de ti y pensar en las ganas que tengo de que llegue ya el día en que venga a Madrid... :( que te echo muchísimo de menos y se me está haciendo muy largo todo este tiempo sin ti.
Un besazo de esos... ya sabes.... ¡ETERNOS!
Hola David,
Muy interesante tu blog, te felicito
Tengo una pregunta, tienes algún ejemplo de cómo hacer un servicio web y como comunicarlo con Moodle
me seria de mucha utilidad
muchas gracias por tu atención
saludos
Martin
Hola David,
me uno a la peticion de Martin en el sentido de si existe o posees algun ejemplo concreto de como hacer un servicio web y comunicarlo con Moodle, te agradeceria enormemente si pudieras ayudarme con eso.
saludos cordiales,
atte.
Cristian
Excelente Post, me gusto mucho el detalle que le distes al tema.
Creo que ya somos 3 personas que nos encontramos interesados en algún ejemplo usando Webservices con Moodle. En mi caso desarrollo en .NET y me gustaría usar los Webservices con esta plataforma.
Saludos y gracias.
Estaré pendiente tu respuesta.