Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Yazı Tipi BoyutlandırıcıAa
  • Anasayfa
  • Teknoloji
    • Siber Güvenlik
    • Yapay Zeka
    • Donanım
    • Bilim
  • Yazılım
  • Savunma & İstihbarat
  • Oyun
  • Yaşam
    • Finans
    • Sinema
    • Dünyadan Haberler
  • İş Birliği
Okuma: RepoWrapped: Bir GitHub Deposu için Spotify Wrapped ve Mücadele Ettiğim API
Paylaş
Yazı Tipi BoyutlandırıcıAa
Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Ara
Bizi Takip Et
  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti
© 2026 Teknomers. All Rights Reserved.

Anasayfa » RepoWrapped: Bir GitHub Deposu için Spotify Wrapped ve Mücadele Ettiğim API

Yazılım

RepoWrapped: Bir GitHub Deposu için Spotify Wrapped ve Mücadele Ettiğim API

teknomers
Son güncelleme: 1 Temmuz 2026 15:55
teknomers
Paylaş
Paylaş

Her yıl Aralık ayında Spotify, kullanıcılara kendi yıl değerlendirmelerini sunar ve sosyal medyada bunların ekran görüntüleri dolaşır. Bu, rakamların her zaman orada olması ve siz onu bir hikaye olarak hiç görmemiş olmanızdan kaynaklanır. Benzer bir şeyi bir GitHub deposu için istiyordum. Bir deponun owner/repo adresini göster, bir katkı sağlayıcı seç, ve sana şunu söyleyen bir sayfa elde et: işte kaç commit yaptın, nerede sıralanıyorsun, işte vahşi haftan. Sonra bunu README’ye bir SVG rozeti yerleştirerek yaşat.

<p>Bu genel başlıktı. Bir hafta sonu, belki. İsim olarak <a href="https://repo-wrapped.tom-girou.dev" target="_blank" rel="noopener noreferrer">RepoWrapped</a>ı seçtim ve ön yüz işleri gerçekten de bir hafta sonu sürdü. Geri kalan zamanım ise gerçekten beklemediğim bir savaşla geçti: <strong>rakamlara GitHub'dan erişmek.</strong></p>

<p>Son zamanlarda yazdığım <a href="https://tom-girou.dev/blog/claude-gitlab-ai-review/" target="_blank" rel="noopener noreferrer">AI güvenliği yazılarından</a> farklı, burada modeller yok; sadece küçük bir Laravel uygulaması ve sizden ne istediğinizi söylemek istemeyen bir API var. Bu, eğlenceli fikrin yan etkisi olduğu, asıl işin beklemediğiniz bir yerde olduğu daha dürüst bir yan proje hikayesi.</p>

<h2>
    <a name="the-idea-is-trivial-the-data-is-not" href="#the-idea-is-trivial-the-data-is-not"></a>
    Fikir basit. Veri değil.
</h2>

<p>"Bir deposunun commit istatistiklerini al" tek bir endpoint gibi görünse de bu gerçek değil. İhtiyacınız olan endpoint'ler, onlara yaklaştığınızda sadece yanıldığınız zaman mantıklı hale geliyor.</p>

<p>Her katkı sağlayıcı için istediğim şeyler: toplam commit sayısı, eklenen ve kaldırılan satır sayısı, haftalık aktivite grafiği, ilk commit tarihleri ve deponun sıralamasındaki yerleri. Bu beş maddenin dördü tek bir GitHub endpoint'inden geliyor: <code>/stats/contributors</code>. Bu endpoint, hikayenin çoğunun geçtiği yer, çünkü içinde iki tuzak var ve ben her ikisine de düştüm.</p>

<h2>
    <a name="trap-one-the-202-that-means-come-back-later" href="#trap-one-the-202-that-means-come-back-later"></a>
    Tuzak bir: 202, "sonra geri dön" anlamına gelir
</h2>

<p>Bir repo için ilk kez <code>/stats/contributors</code> endpoint'ini çağırdığınızda, veri almazsınız. Bir <code>202 Accepted</code> alırsınız ve içi boştur. GitHub, "bunu hesaplamaya başladım, birazdan tekrar sor" diyor.</p>

<p>Sorun değil. Tekrar deniyorsunuz. Fakat "birazdan" belli bir zaman dilimi değil ve büyük bir repo için bu biraz uzun sürebilir. Naif bir tekrar döngüsü ya yavaş bir repoda çok erken pes eder ya da hızlı birinde aşırı yüklenir. Bu yüzden fetch işlemi yavaşlatılır: 1, 2, 4, 8, 16 saniye, beş deneme — çoğu repo bu zaman dilimi içinde çözülür.</p>

<p>Çoğu. Hepsi değil. Ve burada doğru olması gereken kısım: senkron bir web isteği, GitHub'ın bir hesaplamayı bitirmesini bekleyemez. Ziyaretçinin tarayıcı pes eder ve hatta pes etmemiş olsa bile, bir PHP Worker'ı sadece yanıtla ilgisi olmayan bir iş için tutsak tutuyorsunuz.</p>

<p>Bu nedenle bekleme süresi dolduğunda ve GitHub hala 202 döndüğünde, isteği beklemeyi bırakıyorum ve problemi bir kuyruk aracılığıyla çözüyorum. <code>RetryContributorStats</code> işini dağıtıyorum (5 deneme, 30 saniyelik geri çekilme), sayfa hemen elimde olan kısmi verilerle döner — <code>partial: true</code> ile etiketli ki UI dürüstçe "hala hesaplanıyor" diyebilsin — ve iş nihayetinde gerçek sayılar alındığında, bunları kayıtlı veriye ekliyorum. Sayfayı isteyen ziyaretçi beklemiyor. Bir dakika sonra sayfayı açan kişi tamamlanmış hali görüyor.</p>

<p>Ders burada çok açık, ama hızlı hareket ederken es geçilmesi kolay: <strong>herhangi bir dış hesaplama işlemine bir sayfa yüklemesi süresinden daha uzun sürecekse, bunu kontrolörde değil, kuyrukta yer almalıdır.</strong> 202, GitHub'ın önceden nazikçe bunu bildirdiğidir. İlk seferde buna dikkat etmediğim için cezalandırıldım.</p>

<h2>
    <a name="trap-two-the-top100-wall" href="#trap-two-the-top100-wall"></a>
    Tuzak iki: top-100 duvarı
</h2>

<p>İkinci tuzak daha sessizdir, çünkü hata vermez. <code>/stats/contributors</code> yalnızca commit sayısına göre ilk 100 katkı sağlayıcıyı döner. Sarmaladığınız kişi 101. katkı sağlayıcıysa, endpoint temiz, başarılı bir yanıt döner — ama onlar içinde yoktur. Hiçbir bayrak, uyarı yok. Kodunuzun çalışıyor gibi görünüyor, sonra birinin <code>laravel/framework</code> için orta seviye bir katkı sağlayıcıyla denemesi ve sıfırlar ile dolu bir sayfa almasıyla sonuçlanıyor.</p>

<p>"Bana 143. katkı sağlayıcıyı ver" parametresi yok. Dolayısıyla, geriye dönüş, stats endpoint'inin sizin için yapmış olacağı şeyi manuel olarak yapmaktır: kullanıcının commits'ini (ipucu: <code>?author=username</code>) art arda geçmek, her birini açmak ve ekleme ve silme sayısını toplamak. Bu bir N+1 döngüsü ve farkındayım — liste almak için bir istek, her commit için satır sayıları almak için bir istek — bu yüzden 100 commit ile sınırlıdır. Mükemmel değil. Ama "uzun kuyruk için yaklaşık doğru" ya da "kendinden emin sıfır" yerine "doğru" bir şekilde ilerlemek daha iyidir, ve alternatif olan, 101. katkı sağlayıcının var olmadığını varsaymaktır.</p>

<p>Bu yöntemde sadece <code>// N+1 by design</code> olarak etiketlediğim bir yorum bıraktım. En iyi yorumlardan bazıları, gelecekteki sizi "bir şeyi düzeltmeye" çalışmaktan alıkoyandır, ancak bunun kasıtlı bir ödünleşim olduğunu hatırlatır.</p>

<h2>
    <a name="the-firstcommit-trick" href="#the-firstcommit-trick"></a>
    İlk commit hilesi
</h2>

<p>Beşinci sayı — birinin ilk commit tarihinin — herhangi bir endpoint'i yok. Mantıklı yaklaşım, commit geçmişlerini en sona kadar sayfalamak ve uzun ömürlü bir repo üzerinde "en eski olan nedir" yanıtını almak için çok sayıda istek yapmaktır.</p>

<p>GitHub'ın commit endpoint'i paginatörlüdür ve bu paginatörlü yanıtlar <code>Link</code> başlığı taşır; bu başlık <code>rel="first"</code>, <code>rel="prev"</code>, <code>rel="next"</code> ve — faydalı olan — <code>rel="last"</code> içerir. Dolayısıyla: commit listesini <code>per_page=1</code> ile isteyin, başlıktan <code>rel="last"</code> URL'sini okuyun ve bu, doğrudan son sayfayı, yani en eski commit'i göstermektedir. Bir istekte bulunup sayfayı buluyorsunuz, bir başka istekte bulunup onu alıyorsunuz. Tarih boyunca yürümeye gerek yok.</p>

<p>Bir şeyden kaçmış gibi hissettirdi. Ayrıca bu sadece API'nin kendi direktiflerini okumak — paginasyon meta verileri oradaydı, sadece daha önce <code>rel="last"</code>'e ihtiyacım olmamıştı.</p>

<h2>
    <a name="the-caching-because-the-api-has-a-budget" href="#the-caching-because-the-api-has-a-budget"></a>
    Önbellekleme, çünkü API’nin bir bütçesi var
</h2>

<p>GitHub'ın oran sınırı gerçektir ve en iyi durumda bu top-100 geri dönüşü ile beklediğinizden daha yakın olabilir. Bu yüzden, gerekli olmadıkça hiçbir şey yeniden hesaplanmaz. Sonuçlar iki katmana sahiptir: hızlı yol için 1 saatlik TTL olan Redis ve dayanıklı kopya için 24 saatlik Postgres. Bir istek, önce Redis'i kontrol eder, sonra Postgres'i kontrol eder ve ancak gerçek bir eksiklik varsa compute işini piyasaya sürer ve ziyareti <code>/status</code> endpoint'ini anlık olarak takip eden bir yükleme sayfasına düşürür.</p>

<p>Üstüne, GitHub istemcisi için bir token-bucket oran sınırlayıcı layer’ı var — saniyede 10 istek, saatte 4,500, Redis’de izlenir. En az emin olduğum karar burada yaşıyor: Redis down ise, sınırlayıcı <em>atlar</em> ve engellemez. Bir uyarı kaydeder ve isteği kabul eder. "Uygulama çalışmaya devam ediyor, ve GitHub'ı rahatsız edebiliriz" diyerek "Redis bir anda durursa, bütün site 500'de takılır" durumunun tersine tercih ettim. Kişisel bir proje için doğru seçim bu. Gerçek bir etki alanı olan bir şey için karşıt varsayımla başlamak isterdim ve bu bir ödünleşimi tarif etmenin en dürüst yolu; "bu doğru desen" değil, "optimize ettiğim şey bu, ve işte ne zaman değiştiririm"dir.</p>

<h2>
    <a name="the-badge-had-to-be-a-single-file" href="#the-badge-had-to-be-a-single-file"></a>
    Rozetin tek bir dosya olması gerekiyordu
</h2>

<p>Bir README dosyanızda şunu koyarak elde ettiğim kısmen gurur duyduğum kısım, gömülebilir kart. Hemen:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight markdown"><code><span class="p">![</span><span class="nv">RepoWrapped</span><span class="p">](</span><span class="sx">https://repo-wrapped.tom-girou.dev/card/laravel/framework/taylorotwell?theme=dark</span><span class="p">)</span>
    </code></pre>
    <div class="highlight__panel js-actions-panel">
        <div class="highlight__panel-action js-fullscreen-code-action">
            <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on">
                <title>Fullscreen moduna geç</title>
                <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"/>
            </svg>

            <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off">
                <title>Fullscreen modundan çık</title>
                <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"/>
            </svg>
        </div>
    </div>
</div>

<p>ve böylece gizli şekilde render edilen bir SVG elde edersiniz, <code>?theme=</code> ve <code>?hide=</code> ile kontrol edilir. Hiç kimsenin uyarmadığı bir durum vardır: GitHub, README görüntülerini kendi görüntü proxy'si (Camo) aracılığıyla sunar ve bu proxy, SVG’nizi bir kez kendi sunucularından getirir, ne tarayıcı ne de takip eden isteklerle. SVG'nizin yüklemeye çalıştığı herhangi bir şey — bir avatar <code>avatars.githubusercontent.com</code>'dan, dış bir font, her türlü ikinci bir istek — sessizce gerçekleşmez. Yüzde durmalı bir resim alanıyla bir karta sahip olursunuz.</p>

<p>Bu yüzden kartın gerçekten kendi içinde yeterli olması gerekir. Bir <code>image/svg+xml</code> içerik türü ile render edilen bir Blade şablonu ve render edilmeden önce, kontrolör katkı sağlayıcının resmini sunucu tarafında alır ve onu doğrudan SVG'ye bir veri URI olarak embed eder. Tek bir dosya, dışarıdan hiçbir bağımlılık yok, proxy'nin yüklemeyi başaramayacağı bir şey yok. Bir <code><img src=""/></code> biçiminde her yerde çalışır; bu, bir rozeti neden oluşturduğumuzun tüm amacı.</p>

<h2>
    <a name="the-design-briefly" href="#the-design-briefly"></a>
    Tasarım
</h2>

<p>Size genel bir bakış sunacağım, ancak görünüm kasıtlı: bir terminal çıktısı. Yakın siyah bir kanvas, IBM Plex Mono, ekranda %5’in altında kalan bir fosfor yeşili vurgu, verilerin kahramanı olarak beyaz renkten ibaret büyük commit rakamı; bu, süslemeye ihtiyacı yoktur. Gradient topları, cam etkisi yok, küçük trafik ışıkları noktalarıyla süslü sahte pencereler yok. CLI'deki istatistiklerinizi yazdırıyormuş gibi okunan bir tasarıma sahip olmak, bir terminalde yaşayan insanlar için bu tek doğru seçim gibi geldi.</p>

<h2>
    <a name="the-bits-im-not-proud-of" href="#the-bits-im-not-proud-of"></a>
    Gurur duymadığım kısımlar
</h2>

<p>Herhangi bir broşür yazma ruhuyla, iki şey.</p>

<p>Öncelikle, belirsizlik birimi olarak kendimden uzaklaştığım bir önbellek hizmetindeki bir soğuma dalı var — kontrolör ilk önce kendi tazelik kontrolünü yaptığından, yoruma alınmış kod asla etkili olmaz, ama hizmeti izole olarak okuyan herhangi biri kafası karışır ve "karmaşık ama doğru" bir şeyin borcunu ondan hâlâ ödüyorum.</p>

<p>Ve bilmem gereken ve henüz çözmediğim bir yazım hatası var: <code>owner</code> ve <code>repo</code>’yi önbellek anahtarına giderken küçük harfle yazarken, <code>username</code>’yi küçük harfle yazmam. Yani <code>/u/laravel/framework/TaylorOtwell</code> ve <code>/.../taylorotwell</code> için iki farklı önbellek girişine ve iki farklı veritabanı satırına sahip oluyorum, bu da aynı kişi için. Şu ana kadar gerçek bir sorun çıkarmamıştı. Elden bir şekilde bunun başına gelebileceği gün gelecektir. Projenin notlarında yazılı, kesinlikle unutmamak için — çoğu yan projenin hali budur: çalışan bir şey ve yaşamaya karar verdiğiniz kısa bir hata listesi.</p>

<h2>
    <a name="takeaways" href="#takeaways"></a>
    Çıkarımlar
</h2>

<ol>
    <li>
        <strong>Fikir asla çalışma değildir.</strong> "Bir depo için Spotify Wrapped" bir UI ile haftasonu süren bir işti. Gerçek proje ise bir GitHub endpoint'inin üç garipliğiydi. Bir şey basit göründüğünde, veri kaynağı genellikle gerçek mühendisliğin gizlendiği yerdir.</li>
    <li>
        <strong>202 bir tasarım talimatıdır.</strong> Bir API size zaman gerektiğini söylüyorsa, bu, işi istek yolunun dışına almanız ve bir kuyrukta tutmanız için bir işarettir — kontrolörde daha fazla tekrar denemek yerine.</li>
    <li>
        <strong>Sessiz boşluğu değil, gürültülü hatayı ele al.</strong> Top-100 duvarı asla hata vermez. Kendini tür olarak başarı gibi gösteren fakat sessiz bir şekilde kaos yaratan başarısızlıkları görmek, üretim ortamına ulaşır.</li>
    <li>
        <strong>Kendi içinde yeterli, zeki olmaya tercih edilir.</strong> Rozet her yerde çalışıyor çünkü embed eden kimseye hiçbir şey talep etmiyor. Tek dosya, yüklemeler yok, sürpriz yok — bu kısıtlama güçlü kılmadan daraltmıştır.</li>
</ol>

<p>Projem <a href="https://github.com/Kaikina/repo-wrapped" target="_blank" rel="noopener noreferrer">açık kaynak</a>, Laravel 13 ve PHP 8.3 ile, MIT lisanslı. Eğer bunu kendi deponuza yönlendirirseniz ve rakamların doğru görünürse, bu sessiz doğruluk çok daha fazla maliyet getirir ki bu bir güzel sayfanın maliyetidir. Bu genelde böyle oluyor.</p>

<hr/>

<p><em>Orijinal olarak, <a href="https://tom-girou.dev/blog/repo-wrapped/" target="_blank" rel="noopener noreferrer">tom-girou.dev</a>'de yayımlanmıştır.</em></p>

Kaynak: Orijinal Makale

Büyük Laravel Projelerini Nasıl Yapılandırıyorum (Kişisel Mimari Planım)
Bir web sitesi geri bildirim widget’ı geliştirdim, işte neden ve nasıl yaptım
Laravel kuyruğu “Açık dosya sayısı sınırını aştı” hatasıyla karşılaşıyor
Laravel için LMAD MCP – DEV Community
PHP Laravel için BPJS Paket Köprülemesi (VClaim, Aplicare, PCare, i-Care)
Bu Makaleyi Paylaş
Facebook Bağlantıyı Kopyala Yazdır
Paylaş
Önceki Makale Hızlanmak Para Kaybettirir: Daha Yavaş Sürerek Tasarruf Edin!
Sonraki Makale 2026 Siber Güvenlik Değerlendirmesi: Farkındalık ve Dayanıklılık Arasında Kriz

Sanal Medya

FacebookBeğen
452Takip Et
PinterestSabitle
237Takip Et

Son Eklenenler

Acil: Kemp LoadMaster’daki Pre-Auth RCE Açığı Aktif Saldırılara Maruz!
Siber Güvenlik
Google Home Hoparlörü Bize Neler Sunuyor? Gemini Gelişiyor mu?
Liste
Claude, Hacker’a ABD Müzik Festivallerinden Bilet Alma Yolu Gösterdi!
Genel
AçıkCTI’de Suçlu IP ile Göstergeleri Kritik İstihbarata Dönüştürme
Siber Güvenlik
Mario Kart Dünyasında Yeniliklerle Dolu Bir Güncelleme Heyecanı
Oyun
Venice AI’nin 65M$ Seri A Yatırımıyla Unicorn Olması Teknolojide Yeni Bir Dönüm Noktası
Genel
//

Siber güvenlik, yapay zeka ve savunma sanayiinden; finans ve sinema dünyasına uzanan geniş bir yelpaze. Teknomers; teknoloji, strateji ve yazılım dünyasını sade bir dille sizlerle buluşturuyor.

Kurumsal

  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti

Kategoriler

  • Teknoloji
  • Oyun
  • Sinema
  • Siber Güvenlik
  • Bilim
  • Finans
  • Dünyadan Güncel Haberler

Populer

  • TV'de Ücretsiz İzlenebilen Şifresiz Erotik Kanallar (2025 Güncel Frekans Listesi)

  • The Last of Us PC Kontrolleri: Hızlı Silah Değiştirme ve Tüm Tuşlar (2025)

  • Hogwarts Legacy'de Odaklanma İksiri Nasıl Yapılır?

Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Bizi Takip Et
© 2026 Teknomers. All Rights Reserved.
Welcome Back!

Sign in to your account

Kullanıcı Adı veya E-posta Adresi
Şifre

Şifrenizi mi unuttunuz?