Le as estrelas dun repo de GitHub sen esgotar o límite
Resposta rápida
O número de estrelas de calquera repositorio público é un campo dun endpoint, e non precisas token para lelo:
stargazers_count é o número. O endpoint devolve o obxecto completo do repositorio, así que jq está só para sacar un campo de aí.
Esa é toda a resposta se estás a facer un script. O resto do post é a parte que morde cando o pos nunha web: 60 peticións por hora sen autenticar, 5.000 con token, e un contador que chame á API en cada visita cómese calquera das dúas.
O campo, e os que se confunden con el
O obxecto do repositorio trae varios contadores que parecen intercambiables e non o son:
| Campo | Que conta |
|---|---|
stargazers_count | Estrelas. É o número que se ve na páxina do repo |
watchers_count | Historicamente un duplicado do contador de estrelas neste endpoint |
subscribers_count | Xente que de verdade está a vixiar o repo para recibir notificacións |
forks_count | Forks |
Se algunha vez te preguntaches por que watchers_count coincide exactamente coas túas estrelas, é por iso: o nome do campo sobreviviu ao cambio de significado de "starring". Usa stargazers_count e sé explícito.
Os límites, que son o que de verdade decide o teu deseño
A API REST de GitHub permite 60 peticións por hora sen autenticar e 5.000 por hora cun token de acceso persoal. Dous detalles importan máis que os números:
O límite sen autenticar é por enderezo IP. Nun portátil, esa é a túa cota. Nun host de cloud, un runner de CI ou calquera cousa detrás dun NAT compartido, estás a repartir esas 60 peticións por hora co resto de inquilinos do enderezo — que é polo que o mesmo script que ía ben en local empeza a devolver 403 en canto corre en CI.
Ler un repo público tamén conta. Non hai tarifa gratuíta para "só un número". Cada chamada a /repos/{owner}/{repo} gasta unha petición leas un campo ou todos.
Podes comprobar como vas sen gastar cota:
Xuntando as dúas cousas, o deseño cae só: unha web pública non pode chamar á API de GitHub por visitante. Precisa o seu propio endpoint, un token e unha caché.
1 — O teu propio endpoint, co token no servidor
O token vai nunha variable de contorno lida no servidor. Un token enviado ao navegador é un token publicado:
Dúas cousas de aí son correccións ao que este post publicaba antes, e merecen dicirse claras.
catch (err: unknown), non catch (err: Error). A versión anterior deste post anotaba a variable do catch como Error, que non é TypeScript legal — o compilador rexéitao co TS1196, "Catch clause variable type annotation must be any or unknown if specified". É un erro duro, non unha opción de estritez: pódese lanzar calquera cousa, así que o compilador non che deixa afirmar o contrario. Estreita o tipo dentro do bloque se precisas a mensaxe.
Non reenvíes ao cliente a mensaxe de erro de arriba. A versión vella devolvía message: err.message tal cal desde Octokit. Iso filtra: baixo límite de peticións GitHub responde API rate limit exceeded for user ID 12345, que revela o id da conta detrás do token, e cun token revogado responde Bad credentials, o que converte o teu endpoint público nun oráculo en vivo de se o PAT segue a funcionar. Rexistra o detalle no servidor e devolve unha mensaxe plana.
2 — A caché é todo o asunto
A cabeceira Cache-Control de arriba é o que fai de balde o contador:
s-maxage=3600 dille ao CDN que garde a resposta unha hora, así que mil visitantes nesa hora producen unha chamada a GitHub — 1 das túas 5.000, non 1.000. stale-while-revalidate=86400 é a parte que a xente salta: durante un día despois de caducar, o edge segue a servir o último número coñecido mentres refresca por detrás. Se GitHub está caído ou te limitaron, o widget amosa un número algo vello en vez dun erro.
O trato sae barato porque un contador de estrelas non é urxente. Ninguén nota un número de hai cincuenta minutos; todo o mundo nota un widget roto.
3 — O compoñente
Facer o fetch nun useEffect e codificar os estados como números máxicos é o que facía a versión orixinal deste post, e envelleceu mal. 0 significaba cargando, -1 erro, e había unha rama para -2 que ninguén asignaba nunca — código morto renderizando un estado imposible.
Unha libraría de fetching dache os tres estados como estados de verdade:
dedupingInterval importa máis do que parece: sen el, varios compoñentes pedindo a mesma chave montan e cada un lanza a súa petición. Con el, comparten unha.
O compoñente xa renderiza carga, erro e éxito sen inventar valores centinela:
O aria-label non é decoración. Sen el, todo o contido desta ligazón é unha icona de estrela e un número pelado — e mentres carga, un spinner e nada máis. Unha comprobación de accesibilidade nesta web marcouno como ligazón sen nome accesible, anunciada a un lector de pantalla como "ligazón" e sen destino.
Se só precisas o número unha vez
Todo o anterior é para un contador en vivo. Se o número só ten que ser correcto en tempo de build, salta o endpoint e leo en getStaticProps: unha petición por build, sen cota en runtime e sen caché que razoar. Esta web non o fai porque o valor ten que actualizarse entre despregamentos e o blog é estático — o endpoint existe para darlle a unha páxina estática un número vivo.
Os erros que convén lembrar
catch (err: Error)non compila. Usaunknown.- Nunca devolvas a mensaxe de erro de arriba desde un endpoint público.
- As 60 peticións por hora son por IP, e as IPs compartidas compártena.
- Cachea no edge, non nunha variable de módulo — as funcións serverless non a conservan.
stale-while-revalidateé o que converte unha caída nun número algo vello.
Agora mesmo só tes que mirar arriba para ver o resultado, o contador está resaltado cunha estrela.
Por favor, se cres que este contido che axudou ou che gusta, dáme a túa estrela. 🤩
