<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Códice | Entradas sobre «json»</title><description>Feed RSS de publicaciones etiquetadas con json</description><link>https://javguerra.github.io/</link><item><title>De Thunder a Postman</title><link>https://javguerra.github.io/blog/conversor-thunder-postman</link><guid isPermaLink="true">https://javguerra.github.io/blog/conversor-thunder-postman</guid><description>Conversor universal para migrar colecciones API sin perder estructura</description><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/thunder-postman.JGQ6N9Pq_ZW8Q9F.webp&quot; alt=&quot;Logos Thunder Client, Postman y Bruno&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#api&lt;/em&gt;, &lt;em&gt;#json&lt;/em&gt;, &lt;em&gt;#herramienta&lt;/em&gt;, &lt;em&gt;#código&lt;/em&gt;, &lt;em&gt;#javascript&lt;/em&gt;, &lt;em&gt;#node.js&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Necesitaba migrar colecciones de API desde &lt;strong&gt;Thunder Client&lt;/strong&gt; (una extensión de VS Code) a &lt;strong&gt;Bruno&lt;/strong&gt; (cliente API), pero Bruno no importa directamente colecciones de Thunder Client. Sin embargo, Bruno sí importa colecciones de Postman. Así que creé este script que convierte cualquier colección exportada de Thunder Client al formato estándar de &lt;strong&gt;Postman Collection v2.1.0&lt;/strong&gt;, permitiendo importarla en Bruno (o Postman) sin perder carpetas, autenticación, archivos ni estructura. En esta entrada te explico cómo funciona el script.&lt;/p&gt;
&lt;h2 id=&quot;qué-es-bruno&quot;&gt;¿Qué es Bruno?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.usebruno.com/&quot;&gt;Bruno&lt;/a&gt; es un cliente de API de código abierto, offline y respetuoso con la privacidad. A diferencia de otras herramientas, no requiere cuenta, no sincroniza tus colecciones en la nube y todos los datos se guardan localmente en tu ordenador. Es rápido, ligero y perfecto para equipos que priorizan la seguridad y el control de sus propios archivos.&lt;/p&gt;
&lt;h2 id=&quot;planteamiento&quot;&gt;Planteamiento&lt;/h2&gt;
&lt;p&gt;Thunder Client exporta las colecciones en un formato JSON propio. Postman y Bruno usan otro formato diferente. El script actúa como un “traductor” que lee el JSON de Thunder Client, lo interpreta y genera un JSON válido para Postman, conservando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Las peticiones (GET, POST, PUT, DELETE, etc.)&lt;/li&gt;
&lt;li&gt;Las carpetas y subcarpetas&lt;/li&gt;
&lt;li&gt;Los headers, autenticación y cuerpos de las peticiones&lt;/li&gt;
&lt;li&gt;Los archivos adjuntos en formularios&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Puedes descargar el script desde el: &lt;a href=&quot;https://github.com/JavGuerra/conversor-thunder-postman&quot;&gt;&lt;button&gt;Repositorio del conversor&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;dificultades-de-la-conversión&quot;&gt;Dificultades de la conversión&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Estructura inconsistente del JSON de Thunder Client&lt;/strong&gt;&lt;br&gt;
Las exportaciones no siguen un formato fijo: las peticiones pueden estar en &lt;code&gt;requests&lt;/code&gt;, en &lt;code&gt;items&lt;/code&gt;, en &lt;code&gt;tests&lt;/code&gt; o en arrays con nombres personalizados como &lt;code&gt;requests_carpeta_auth&lt;/code&gt;. El script tuvo que aprender a buscar en cualquier lugar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Carpetas anidadas sin un identificador claro&lt;/strong&gt;&lt;br&gt;
Thunder Client a veces usa &lt;code&gt;parentId&lt;/code&gt;, otras veces &lt;code&gt;_parentId&lt;/code&gt;, o simplemente anida objetos. Reconstruir la jerarquía a cualquier nivel requirió una función recursiva robusta.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Variables en URLs&lt;/strong&gt;&lt;br&gt;
Thunder Client permite &lt;code&gt;{{variables}}&lt;/code&gt; en las URLs. Si intentas parsear la URL con &lt;code&gt;new URL()&lt;/code&gt;, el script falla. Hubo que detectar y proteger estos casos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Autenticación dispersa&lt;/strong&gt;&lt;br&gt;
La autenticación puede venir en un bloque &lt;code&gt;auth&lt;/code&gt; o directamente en los headers. Además, hay que soportar Bearer, Basic y API Key (que puede ir en header o en query param).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Archivos en formdata&lt;/strong&gt;&lt;br&gt;
Los archivos no se representan como strings simples, sino como objetos con ruta o strings especiales (&lt;code&gt;@/ruta&lt;/code&gt;). Hay que identificarlos y convertirlos al formato que espera Postman.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Headers con espacios&lt;/strong&gt;&lt;br&gt;
Algunos headers exportados tenían espacios al inicio o final del nombre, lo que provocaba errores en Bruno. Hubo que limpiarlos con &lt;code&gt;trim()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BOM en archivos Windows&lt;/strong&gt;&lt;br&gt;
Los archivos exportados desde Windows incluyen una marca de orden de bytes (BOM) invisible que rompe el parseo JSON. Hubo que detectarla y eliminarla.&lt;/p&gt;
&lt;h2 id=&quot;el-script-paso-a-paso&quot;&gt;El script paso a paso&lt;/h2&gt;
&lt;h3 id=&quot;1-lee-el-archivo-de-entrada&quot;&gt;1. Lee el archivo de entrada&lt;/h3&gt;
&lt;p&gt;El script recibe como parámetro el archivo JSON exportado desde Thunder Client. Verifica que el archivo existe y que es un JSON válido. Si el archivo tiene BOM (marca de orden de bytes típica de Windows), lo elimina automáticamente para evitar errores.&lt;/p&gt;
&lt;h3 id=&quot;2-extrae-todas-las-peticiones&quot;&gt;2. Extrae todas las peticiones&lt;/h3&gt;
&lt;p&gt;Busca las peticiones en &lt;strong&gt;cualquier lugar&lt;/strong&gt; del JSON: en la raíz, dentro de carpetas, en arrays con nombres personalizados, etc. No importa cómo haya estructurado Thunder Client la exportación.&lt;/p&gt;
&lt;h3 id=&quot;3-extrae-la-estructura-de-carpetas&quot;&gt;3. Extrae la estructura de carpetas&lt;/h3&gt;
&lt;p&gt;Identifica las carpetas y subcarpetas, detectando sus identificadores (&lt;code&gt;folderId&lt;/code&gt;, &lt;code&gt;parentId&lt;/code&gt;) para reconstruir la jerarquía original, incluyendo &lt;strong&gt;subcarpetas anidadas a cualquier nivel&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;4-convierte-cada-petición-individualmente&quot;&gt;4. Convierte cada petición individualmente&lt;/h3&gt;
&lt;p&gt;Para cada petición, traduce:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;URL&lt;/strong&gt;: La segmenta en partes (host, path, query params) para Bruno, pero respeta las variables &lt;code&gt;{{variable}}&lt;/code&gt; sin intentar parsearlas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headers&lt;/strong&gt;: Los mantiene y limpia espacios accidentales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autenticación&lt;/strong&gt;: Soporta Bearer Token, Basic Auth y API Key (tanto en header como en query param).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cuerpo (body)&lt;/strong&gt;: Maneja JSON (con resaltado de sintaxis), formularios multipart (con detección automática de archivos) y urlencoded.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;5-construye-la-colección-postman&quot;&gt;5. Construye la colección Postman&lt;/h3&gt;
&lt;p&gt;Reconstruye la jerarquía completa usando recursividad: carpetas raíz, subcarpetas y peticiones en su lugar correspondiente. Si la exportación no incluye identificadores, usa un método alternativo como respaldo.&lt;/p&gt;
&lt;h3 id=&quot;6-guarda-el-resultado&quot;&gt;6. Guarda el resultado&lt;/h3&gt;
&lt;p&gt;Escribe el archivo JSON en el formato estándar de Postman Collection v2.1.0, listo para importar.&lt;/p&gt;
&lt;h3 id=&quot;7-muestra-estadísticas&quot;&gt;7. Muestra estadísticas&lt;/h3&gt;
&lt;p&gt;Al finalizar, informa sobre cuántas peticiones y carpetas se han convertido.&lt;/p&gt;
&lt;h2 id=&quot;el-resultado-características-principales-destacadas&quot;&gt;El resultado: características principales destacadas&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Qué hace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jerarquía completa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Respeta carpetas y subcarpetas anidadas a cualquier nivel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Búsqueda exhaustiva&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Encuentra peticiones estén donde estén en el JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Autenticación múltiple&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bearer, Basic y API Key (header o query)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Soporte para archivos&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Detecta y convierte campos de tipo file en formularios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compatibilidad con Bruno&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Segmenta el host y limpia rutas para importación perfecta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resaltado JSON&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Configura los cuerpos JSON para que se vean con colores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Manejo robusto&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Valida archivos, limpia BOM, muestra errores claros&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sin dependencias&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usa solo módulos nativos de Node.js&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;ejemplo-de-uso&quot;&gt;Ejemplo de uso&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; convertir-thunder-a-postman.js&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; prueba-thunder.json&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; coleccion-postman.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Salida esperada:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✅ Conversión completada con éxito.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;🚀 Fichero generado: coleccion-postman.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;📊 Peticiones: 24 | Carpetas: 7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;limitaciones-del-script&quot;&gt;Limitaciones del script&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Variables de colección&lt;/strong&gt;: No se importan automáticamente (deben recrearse a mano)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scripts pre-request y tests&lt;/strong&gt;: No se convierten (la API es compatible, pero hay que copiarlos manualmente)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autenticación avanzada&lt;/strong&gt;: OAuth 2.0, AWS Signature y Digest no están soportados&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/conversor-thunder-postman&quot;&gt;Repositorio desde donde descargar el conversor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.usebruno.com/&quot;&gt;Cliente Bruno&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/thunder-postman.JGQ6N9Pq_ZW8Q9F.webp"/><category>api</category><category>json</category><category>herramienta</category><category>código</category><category>javascript</category><category>node.js</category><author>JavGuerra</author></item></channel></rss>