Parte 7 de 11
Proyectos con la GitHub API
Cargar los repositorios en vivo, cachear en el navegador y manejar los estados de carga y error.
Lo mejor de una web personal es no tener que actualizar los proyectos a mano: la página los lee directamente de GitHub.
El endpoint
La API pública de GitHub permite listar los repos de un usuario:
https://api.github.com/users/tu-usuario/repos?per_page=100&sort=updated
Devuelve un JSON con todos los repos y sus metadatos: nombre, descripción, lenguaje, estrellas, forks, enlace…
El módulo github.ts
Un archivo con la lógica, tipado con TypeScript y con cache para no llamar a la API más de lo necesario (la versión sin autenticar tiene límite de peticiones por hora):
export async function getRepos(username: string) {
const cacheKey = `github-repos:${username}`;
const cached = readCache(cacheKey);
if (cached) return cached;
const response = await fetch(
`https://api.github.com/users/${username}/repos?per_page=100&sort=updated`
);
if (!response.ok) throw new Error(`GitHub API: ${response.status}`);
const repos = await response.json();
writeCache(cacheKey, repos);
return repos;
}
El cache guarda el resultado en localStorage con una marca de tiempo y lo invalida a las 24 horas:
const TTL = 24 * 60 * 60 * 1000;
function readCache(key: string) {
const raw = localStorage.getItem(key);
if (!raw) return null;
const data = JSON.parse(raw);
if (Date.now() - data.fetchedAt > TTL) {
localStorage.removeItem(key);
return null;
}
return data.repos;
}
function writeCache(key: string, repos: unknown[]) {
localStorage.setItem(key, JSON.stringify({ fetchedAt: Date.now(), repos }));
}
La página de proyectos
La página muestra un estado inicial “Cargando…”, y luego tarjetas. Si algo falla, muestra un mensaje con un botón para reintentar. Todo con un <script> en la página:
<script>
import { getRepos } from '../scripts/github';
const container = document.querySelector('#projects');
const username = container?.getAttribute('data-username') ?? '';
async function load() {
if (!username) {
setStatus('No se ha configurado el usuario de GitHub.');
return;
}
try {
const repos = await getRepos(username);
renderCards(repos);
} catch {
setStatus('No se pudieron cargar los proyectos. Reintenta más tarde.');
}
}
void load();
</script>
El nombre de usuario se pasa sin hardcodear en el JS, mediante un atributo data-username que el servidor rellena desde la variable de entorno.
Detalle de seguridad: al pintar datos que vienen de fuera (la API) con
innerHTML, siempre sanitizo el texto para escapar<,>,&… así un nombre raro de repo no se convierte en HTML malicioso.
En la siguiente parte, todo lo que los buscadores necesitan para encontrar la web.