Trabajando con la API de Confluence

By   Skrigueztep Skrigueztep Thu Aug 22 2024

Desde hace no mucho, estaba desarrollando una herramienta (que espero se pueda sacar pronto como un proyecto Open Source), la cual ha ido evolucionando, en el relativo poco tiempo, y de forma natural; y gracias a esta evolución he logrado ver la posibilidad de extender su funcionalidad y poder automatizar partes de cierto proceso, agregando varios servicios y aligerando mi carga de trabajo en ciertas actividades.

Dentro de las cuales se encuentran, relacionadas con Git, GitLab, Jira y Confluence. En este caso me adentré en el consumo de la API de Confluence y el desarrollo de alguna que otra característica usando dicha API y te cuento parte del proceso.

Conectando con la API

Si ya has trabajado con la API de Confluence o Jira puedes saltarte esta parte.

Anteriormente trabaje con la API de Jira y su documentación está relativamente sencilla aunque con algunas deficiencias pero en general ya cuando le entiendes y de funciona la conexión de forma exitosa; todo es más sencillo. Y ya que tanto Jira como Confluence con productos de la empresa Atlasssian, su documentación es muy similar y podemos reutilizar parte del código que ya se tenia anteriormente

Lo principal es ir a la documentación oficial, y como en el caso de Jira, ver el como establecer la comunicación con la API y que se requiere. Es relativamente sencillo pero podemos darnos una idea de como conectar por medio de los ejemplos que ponen para usar sus endpoints

Como podemos ver, el endpoint se conforma de la siguiente forma:

https://{your-instance}.atlassian.net/wiki/api/v2/{endpoint}

Además de que es necesario agregar el header de Basic Auth para poder tener acceso a la información. En nuestro caso, nos ahorramos esta configuración ya que uno de mis paquetes ya lo tenía de fácil uso, simplemente fue utilizar el código existente. Aquí el código de implementación:

El objetivo

Esto es simple a grandes rasgos, simplemente poder crear una nueva hoja con contenido especifico dentro de un space dado.

Pero para esto, al momento de tratar de crear la hoja se pide cierta información como se detalla en la documentación del endpoint, create page:

Como se puede observar uno de los requisitos para crear una hoja es pasarle el spaceId del space en donde se va a crear. Para ello primero teníamos que solucionar el como traer el space que buscamos y después persistir ese space especifico para poder utilizar su información.

Buscando el space

Para poder obtener obtener la información de los spaces y buscar el especifico, de acuerdo con la documentación se pueden traer todos con o sin filtros y también se puede obtener solo uno por medio de su id, el que a nosotros nos interesó fue el de obtener todos pero filtrados, ya que solo limitamos la búsqueda por ids, keys y tipo para no hacer una búsqueda tan exhaustiva en primer lugar.

Intentando crear una hoja

Ahora… lo lo que viene es fácil, ya que para agregarle el contenido a la hoja solo hay que agregarlo en forma de string , una simple cadena de texto, en el atributo value dentro del objeto body, como en el ejemplo:

Y hasta aquí todo bien, ya tenemos la hoja lista y creada, obviamente llenando los campos con la información correspondiente. Pero si has utilizado confluence, sabrás que se ve distinto cuando pegas un texto recién copiado y con el formato a cuando pegas un texto sin formato, ya que se ajusta al formato de confluence mismo y para ello entramos en la parte divertida, el ADF o Atlassian Document Format, que es un formato en especifico que usa confluence para su editor rico en texto.

Creando la hoja

Anteriormente para poder seguir el formato definido de acuerdo con el schema de ADF, existía la dependencia adf-utils pero ya entró en desuso y el reemplazo oficial recomendado es la dependencia @atlaskit/adf-utils, lo malo de todo esto es que no existe documentación relacionada para ello o al menos públicamente.


Aquí cabe recalcar que la necesidad que tenía era pasar de un formato markdown a ADF pero personalmente no recurro a usar dependencias externas a menos de que sea muy necesario o que el beneficio sea mayor que el riesgo, tanto de mantenimiento como de seguridad.


@atlaskit/adf-utils

Entonces la forma más natural que tenia hasta el momento era pasar casi de forma manual cada caso que tuviera en el markdown a ADF por medio de leer linea por linea y quedó algo como esto:

Y todo esto al final se convertía en una cadena texto de la siguiente forma:

Esto hacía que gracias a los “bloques” que expone la dependencia se pueda tener el formato pero esto manda básicamente un error 400 por que no se puede transformar el objecto al llegar al servicio y está tronando a cada rato específicamente con las tablas, links, entre otros…

@markdown-confluence/lib

Después de unos días de romperme la cabeza y de un poco de frustración, decidí darme por vencido; ya que solo estaba teniendo errores y en algún momento me llego la idea de buscar la forma oficialmente de poder validar que el formato ADF generado fuera valido, entonces al buscarlo me encontré con algunas dependencias que ofrecían hacer el trabajo por mi y las opciones fueron:

Que pasa con esta dependencia? Pues solo es porque no tiene mucho uso, la ultima publicación fue hace 8 meses y realmente es muy sencilla, si vamos al código y a las dependencias, realmente no hace gran cosa y está bien pero básicamente solo usa las dependencias oficiales y pues me da la sensación de que se puede hacer un poco más directo.

Entre algunas opciones que fueron surgiendo el que más completo y fiable se notaba era:

@markdown-confluence/lib

Con esta opción si me rendí y decidí usarla, pero resulta que tuve varios problemas a la hora de usarla, ya que estoy trabajando con CommonJS, en una dependencia intermedia y cuando trataba de migrar o de aceptar tanto ECMA Script Modules y CommonJS pues fueron habiendo problemas a la hora de usar en un proyecto… realmente no pude solucionar esta parte y fue más complicado o complejo y finalmente volviendo a lo mismo, revisar las dependencias y el código; me encuentro con que usa de igual forma las dependencias oficiales y que el código si bien es más complejo y con alguna funcionalidad mejor, tiene pocas descargas, hace un año que no se actualiza o más bien que no se publica una nueva versión y aún creo que podemos hacer algo de una forma más simple o sencilla

Finalmente le mandaba la parte de content como un string por medio de JSON.stringify

@atlaskit/editor-markdown-transformer

Y antes de darme por vencido y votar todo… pues resulta que al estar viendo el código, estaba pasando entre los repositorios de atlassian y me encontré con varios repos pero en especifico con el que se estaban basando las dependencias y me llamo la atención, entonces de chismoso viendo el funcionamiento pues decidí probar que tal y si funcionaba.

Pues lo instalé y el ejemplo más simple era lo siguiente:

en donde value, como ya mencioné pues es el contenido con formato markdown en string.

Y al mandarlo pues básicamente dio lo mismo, pero entonces; como el no regresa detalles específicos de los errores y no hay validador de que le duele, pues recuerdo que hay una sección dentro de la documentación acerca de como saldría un documento ADF desde el editor de confluence:

Anteriormente no estaba la opción de Document Viewer pero cuando la vi pues resulta que sale esto:

Entonces pues ya podía saber más o menos como o por donde probar y comencé por lo básico.

Gracias al Playground de Typescript, logré pasar la información en crudo y convertirlo a string, pero justo ese JSON que obtenía lo podía pasar directo a viewer. Entonces de un objeto tan grande como este:

Pues comenzamos con esto:

Y fuimos agregando cada elemento dentro del array content principal hasta volver a tener el objeto completo, pero cuando se agregaba una linea y algo fallaba, se fue limpiando el nodo que daba error hasta que el viewer lo aceptaba por completo.

Entonces dentro del string tuvimos que localizar cada cosa que fallara y eliminarla. Termínanos haciendo lo siguiente:

Ya que se observó que los valores null o vacios, principalmente, causaban los errores en el viewer, además de algunos otros atributos que por el momento nosotros no necesitábamos ocupar.

Por último, ya con el reemplazo del contenido o de la info se hizo una prueba tratando de crear la hoja con el contenido y ver si efectivamente se respetaba el formato y lo que obtuvimos fue:

Entonces si se logró con éxito crear la hoja y al validarlo efectivamente ya tenia el formato deseado, solo con algunos detalles entre estilos por unas macros pero ya sería un detalle menos y que por el momento podemos aceptar.


En los siguientes días espero por este medio, poder hacer el anuncio de cuando por fin pueda exponer los wrappers de los servicios tanto de Jira, Confluence y GitLab no por completo obviamente pero si les iré poniendo cariño constantemente.


Por el momento eso es lo que llevo, así que al final de este artículo vienen los medios por los cuales puedes seguir lo que voy publicando. Espero te haya gustado esta pequeña experiencia y pato-aventura de un día en el desarrollo.

Happy coding 🖖