<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joshua Terrones</title>
    <description>The latest articles on DEV Community by Joshua Terrones (@joshuaterrones).</description>
    <link>https://dev.to/joshuaterrones</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3057483%2Ffb02916f-8ad2-4e1d-9f34-81e3d8501f6f.webp</url>
      <title>DEV Community: Joshua Terrones</title>
      <link>https://dev.to/joshuaterrones</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joshuaterrones"/>
    <language>en</language>
    <item>
      <title>Automaticé la publicación de mi blog a Dev.to</title>
      <dc:creator>Joshua Terrones</dc:creator>
      <pubDate>Thu, 24 Sep 2026 10:16:16 +0000</pubDate>
      <link>https://dev.to/joshuaterrones/automatice-la-publicacion-de-mi-blog-a-devto-5bl8</link>
      <guid>https://dev.to/joshuaterrones/automatice-la-publicacion-de-mi-blog-a-devto-5bl8</guid>
      <description>&lt;p&gt;Acabo de automatizar el flujo completo de publicación de mi blog. Ahora escribo un post en Sanity Studio, le doy Publish, y en 10 segundos aparece en dos sitios a la vez: en mi portafolio (josht.xyz) y en Dev.to.&lt;/p&gt;

&lt;h2&gt;
  
  
  El flujo completo
&lt;/h2&gt;

&lt;p&gt;Antes tenía que copiar el contenido, pegarlo en el editor de Dev.to, subir las imágenes manualmente y ajustar el formato. Un proceso de 15 minutos por post. Ahora es automático.&lt;/p&gt;

&lt;p&gt;La arquitectura es simple pero efectiva:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Escribo el post en Sanity Studio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Al publicar, Sanity dispara un webhook con el ID del documento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mi API Route en Next.js recibe el webhook, consulta el post completo vía GROQ y lo convierte a Markdown.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Llama a la API de Dev.to con el contenido y un canonical_url que apunta a mi dominio.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  El detalle del canonical
&lt;/h2&gt;

&lt;p&gt;El canonical_url es lo más importante de toda la integración. Le dice a Google y a Dev.to que la versión "oficial" del contenido vive en mi sitio, no en Dev.to. Esto evita penalizaciones por contenido duplicado en SEO y me mantiene el tráfico.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los problemas que encontré
&lt;/h2&gt;

&lt;p&gt;Dev.to no acepta URLs con http:// en el canonical_url. Hay que usar siempre https://. Lo descubrí a la mala, con un error 422 que no explicaba nada hasta que leí la documentación con calma.&lt;/p&gt;

&lt;p&gt;También hay que asegurarse de que el dominio no esté redirigiendo. Si josht.xyz redirige a &lt;a href="http://www.josht.xyz" rel="noopener noreferrer"&gt;www.josht.xyz&lt;/a&gt;, el webhook de Sanity falla con un 308 antes de llegar a mi código. Es un detalle que parece obvio pero que cuesta ver si no lo estás esperando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que viene
&lt;/h2&gt;

&lt;p&gt;Por ahora el flujo funciona solo de Sanity a Dev.to. En el futuro quiero añadir lo inverso: que si alguien comenta o reacciona en Dev.to, se refleje de alguna forma en mi sitio. Pero eso es otro proyecto.&lt;/p&gt;

&lt;p&gt;Mientras tanto, ya tengo el sistema que quería. Escribo una vez, publico en dos lugares, sin copiar y pegar.&lt;/p&gt;

</description>
      <category>devlog</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>sanity</category>
    </item>
    <item>
      <title>Conecté mi portafolio a APIs reales: GitHub, Hackatime y Sanity</title>
      <dc:creator>Joshua Terrones</dc:creator>
      <pubDate>Thu, 24 Sep 2026 10:00:31 +0000</pubDate>
      <link>https://dev.to/joshuaterrones/conecte-mi-portafolio-a-apis-reales-github-hackatime-y-sanity-4b27</link>
      <guid>https://dev.to/joshuaterrones/conecte-mi-portafolio-a-apis-reales-github-hackatime-y-sanity-4b27</guid>
      <description>&lt;p&gt;Durante las últimas semanas estuve construyendo mi portafolio personal en Next.js 16. Al principio todo era maquetación pura: los proyectos mostraban "Proyecto 01, Proyecto 02, Proyecto 03", las horas de código decían "000h", y el blog era un array hardcodeado con tres posts de prueba. Un esqueleto precioso, pero vacío.&lt;/p&gt;

&lt;p&gt;Esta semana decidí conectarlo todo a APIs reales. Este post es la bitácora completa del proceso, incluyendo los errores que me costaron más tiempo del que me gustaría admitir.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub API: la primera integración
&lt;/h2&gt;

&lt;p&gt;Lo primero que quise resolver era que la Home mostrara mis proyectos reales en lugar de placeholders. Después de investigar un poco descubrí algo importante: la API REST de GitHub no expone los repositorios "pinned" (los que eliges manualmente en tu perfil). Solo devuelve todos los públicos.&lt;/p&gt;

&lt;p&gt;Para obtener los pinned reales hay que usar la API GraphQL, que sí permite consultar los pinnedItems de un usuario. Así que terminé con una arquitectura híbrida:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GraphQL → para los repos destacados en la Home.&lt;br&gt;
REST → para el listado completo en /proyectos.&lt;br&gt;
Ambas con caché de 24 horas vía next: { revalidate: 86400 }.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hackatime: las horas que realmente programo
&lt;/h2&gt;

&lt;p&gt;Hackatime es un fork abierto de WakaTime que usa Hack Club para trackear horas de código. Registra tus editors y te da estadísticas reales: cuántas horas programaste, qué lenguajes usas más, racha de días activos.&lt;/p&gt;

&lt;p&gt;La API devuelve un JSON muy limpio. Un ejemplo real de mi cuenta, con el rango del año completo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;total_seconds: 45725 → 12h 42m&lt;br&gt;
TypeScript: 43.29%&lt;br&gt;
Other: 38.81%&lt;br&gt;
XML: 18.6%&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Solo necesité configurar el API key en .env.local y hacer un fetch con la fecha de inicio del año. Los datos se muestran en /sobre-mi con barras de progreso por lenguaje.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanity: el blog que ya no es un array
&lt;/h2&gt;

&lt;p&gt;Esta fue la parte más larga. Mi blog originalmente era un archivo posts.ts con tres posts hardcodeados. Funcionaba, pero cada vez que quería publicar algo tenía que editar código, commitear y esperar el deploy.&lt;/p&gt;

&lt;p&gt;Sanity es un CMS headless que se embebe dentro de tu propia app de Next.js. Escribes posts desde /studio, se guardan en sus servidores, y tu blog los lee vía queries GROQ.&lt;/p&gt;

&lt;p&gt;Un detalle que casi me vuelve loco: al embeber el Studio en Next.js, el CORS por defecto solo permite localhost:3333 (el puerto del Studio independiente), no el 3000 de tu app. Hay que añadirlo explícitamente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx sanity cors add &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; --credentials&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ese flag --credentials es crítico. Sin él, el Studio puede cargar pero el login se queda en un bucle infinito porque el navegador no envía las cookies de sesión.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendí
&lt;/h2&gt;

&lt;p&gt;Tres lecciones que me llevo de esta integración:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;La API REST de GitHub no sirve para repos pinned. Hay que usar GraphQL. Perdí una hora intentando resolverlo con REST antes de leer la documentación oficial.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;La caché no es opcional. Si cada visita hace un fetch a la API, revientas el rate limit en un día. Con revalidate: 86400 consumes 3 requests al día en vez de 3000.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Los errores de CORS son silenciosos y confusos. El login de Sanity no daba ningún mensaje de error claro — solo un bucle infinito. La solución estaba en un flag de configuración que no aparece en el tutorial básico.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Lo que viene
&lt;/h2&gt;

&lt;p&gt;Todavía queda trabajo: conectar este blog a Dev.to para publicar automáticamente, añadir un formulario de contacto con Resend, y eventualmente soporte bilingüe (español/inglés) con next-intl.&lt;/p&gt;

&lt;p&gt;Pero por ahora, el portafolio ya no es un esqueleto. Muestra proyectos reales, cuenta las horas que programo de verdad, y tiene un blog que puedo actualizar sin tocar una sola línea de código.&lt;/p&gt;

&lt;p&gt;Eso se siente bien.&lt;/p&gt;

</description>
      <category>devlog</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>sanity</category>
    </item>
  </channel>
</rss>
