DEV Community

Cover image for 1 Saatimi Yakan API Hatası ve Çözümü
Serdar Tavukçu for Serdar Tavukçu

Posted on

1 Saatimi Yakan API Hatası ve Çözümü

gorsel

Olay nasıl başladı

Bir sabah kahvemi alıp bilgisayarın başına oturdum. Amacım basit bir otomasyon scripti yazıp yayın servisine birkaç makale göndermekti. Python ile hızlıca bir şeyler karaladım. Okuma işlemleri için GET istekleri atıyordum. Kullanıcı bilgilerimi çekmek için yazdığım kod tıkır tıkır çalışıyordu. Yanıt kodu 200 geliyordu ve veriler ekranıma dökülüyordu. Her şey yolunda gidiyor gibiydi. Ancak iş yazma kısmına, yani POST isteğine geldiğinde duvara çarptım. Sunucu bana inatla 403 hatası döndürüyordu. İşin en sinir bozucu yanı ise gelen yanıtın gövdesinin tamamen boş olmasıydı. Hata mesajı yok, açıklama yok, sadece koca bir 403.

Kendi kendime acaba kimlik bilgilerim mi yanlış diye sordum. Belki de yetkim yetmiyordu. Defalarca token değerimi kontrol ettim. Hatta yeni bir token aldım ama sonuç değişmedi. Python kullanırken genelde her şeyin otomatik halledileceğini düşünürüm. Bu kez öyle olmadı. Kendi yazdığım kodun neden hata verdiğini anlamak için saatlerimi harcadım. İlk başta sorunun hesap yaşımdan ya da sistemin beni bot olarak işaretlemesinden kaynaklandığını sandım. Oysa gerçek bambaşkaymış. Bir anlık sinirle tüm kod yapısını değiştirmeyi bile düşündüm. Neyse ki sakin kalıp mantıklı bir yol izlemeye karar verdim.

Bu nerede karşına çıkar

Bu tip bir durumla herhangi bir API ile çalışırken karşılaşman işten bile değil. Özellikle modern web servislerinin önünde duran koruma katmanları bazen çok agresif davranabiliyor. Sen sadece kendi scriptinle veri çekmeye çalışıyorsun ama servis senin bir tarayıcı mı yoksa bir bot mu olduğunu anlamak istiyor. Benim başıma gelen bu olay, aslında pek çok geliştiricinin yaşadığı klasik bir iletişim kopukluğu. Özellikle sunucu tarafında Varnish gibi bir katman varsa, senin isteklerini doğrudan reddedebilir.

Bunu sadece yayın servislerinde değil, borsa verisi çekerken ya da bir ticaret platformuna veri gönderirken de yaşayabilirsin. Özellikle Python kütüphaneleri varsayılan olarak kendi kimliklerini bir başlıkta taşırlar. Eğer sunucu bu varsayılan kimliği sevmiyorsa, senin ne kadar haklı olduğunun bir önemi kalmaz. Kapı duvar olur. Bu sorunla karşılaştığında hatanın senin kodunda mı yoksa sunucuda mı olduğunu anlamak bazen saatler sürebilir. İnsan kendi yazdığı koda güvenmek istiyor ama bazen kodun dışındaki etkenler tüm süreci kilitliyor. Bu durum aslında geliştirme yaparken en sık rastlanan ama en az konuşulan engellerden biri.

Geliştirme ortamında yerel bir sunucuya istek atarken hiçbir sorun yaşamayıp canlı ortama geçtiğinde bu 403 hatasını almak oldukça yaygındır. Yerel ağda güvenlik duvarı kuralları daha esnek tutulurken, canlı sunucularda her gelen istek sıkı bir denetimden geçer. Özellikle kurumsal API servisleri, kaynağı belirsiz veya teknik başlıkları eksik olan tüm trafiği otomatik olarak reddetmek üzere yapılandırılmıştır. Bu durum, özellikle veri kazıma veya otomatik içerik girişi yapan araçlarda, projenin daha ilk aşamasında geliştiriciyi durduran en büyük engeldir.

Kök neden

Sorunun temelinde yatan şeyi bulmak için biraz dedektiflik yapmam gerekti. Hata mesajı vermeyen bir 403 kodu, genellikle sunucunun senin kimliğini beğenmediği anlamına gelir. Yanıt başlıklarını incelediğimde server kısmında Varnish ifadesini gördüm. Bu, isteğimin uygulamaya bile ulaşmadan bir ön katmanda engellendiğini gösteriyordu. Python istemcisinin varsayılan olarak gönderdiği başlık, bu katman tarafından doğrudan kara listeye alınmıştı.

Aslında ortada çok karmaşık bir durum yoktu. Sadece bir kimlik uyuşmazlığı vardı. Hesap bilgilerim, hedef alanım veya sistemdeki konumumla ilgili hiçbir sorun yoktu. Tek suçlu, isteğin başlık kısmında eksik olan o küçük bilgiydi. Sunucu, gelen isteğin arkasında bir tarayıcı olmadığını anladığı anda bağlantıyı kesiyordu. Ben ise sorunu kendi kodumun derinliklerinde arayarak vakit kaybediyordum. Oysa çözüm, sunucunun beklediği o küçük nezaket kuralını yerine getirmekten ibaretti. Bu, deneyimsizlikten ziyade, sistemlerin çalışma mantığını göz ardı etmenin getirdiği bir körlüktü.

Çözüm

Sorunu çözmek için yapmam gereken şey çok basitti. İsteklerime bir kimlik, yani User-Agent başlığı eklemeliydim. Bunu yapmak için Python kütüphanesinin sunduğu başlık parametresini kullandım.

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}

response = requests.post('https://api.ornek.com/articles', headers=headers)
print(response.status_code)
Enter fullscreen mode Exit fullscreen mode

Bu kod parçası, isteğin içine sanki bir web tarayıcısından geliyormuş gibi bir kimlik ekliyor. Bunu ekledikten sonra POST isteğim anında 200 cevabını döndürdü. Daha önce aldığım 403 hatası, doğru başlığı gönderdiğim anda yok oldu.

Yolda çıkan hatalar

Bu çözüme ulaşmadan önce çok fazla zaman kaybettim. İlk hatam, sorunun token veya yetkilendirme kaynaklı olduğunu varsaymaktı. Bu yüzden defalarca token yeniledim. İkinci hatam ise hatayı anlamak için deneme yanılma yöntemini çok düzensiz yapmaktı. Accept başlığını değiştirmeyi denedim, 403 aldım. Accept başlığını tamamen kaldırdım, yine 403 aldım. Accept değerini json olarak ayarladım, sonuç yine değişmedi.

Tüm bu denemeler aslında birer zaman kaybıydı çünkü değişkenleri tek tek izole etmiyordum. Bir şeyi değiştirip sonucu görmeye çalışmak yerine, hepsini aynı anda değiştirmeye çalışıyordum. Bu da hangi değişikliğin işe yaradığını anlamamı engelliyordu. Sonunda her şeyi bir kenara bırakıp sadece User-Agent başlığını eklediğimde sorunun çözüldüğünü gördüm. Eğer en başta değişkenleri tek tek izole etseydim, bu işlem sadece bir dakikamı alırdı. Hata ayıklama sürecinde en büyük düşmanım, kendi varsayımlarım oldu.

Karşılaştırma

Bu sorunu çözmek için başka yollar da vardı tabii. Mesela farklı bir kütüphane kullanabilirdim ya da tüm isteği bir tarayıcı otomasyon aracı üzerinden geçirebilirdim. Ancak bu yöntemler çok daha ağır ve gereksizdi. Bir API isteği için koca bir tarayıcıyı ayağa kaldırmak, sinek öldürmek için top kullanmaya benziyor.

Başka bir alternatif ise proxy kullanmaktı ama bu da sorunu çözmek yerine sadece maskelemeye yarardı. Benim amacım sunucuyla düzgün bir şekilde konuşmaktı, onu kandırmak değil. Bu yüzden doğrudan başlık ekleme yöntemini seçtim. Hem en temiz yol buydu hem de performans açısından en verimli olanı. Kodumun hafif kalmasını istiyordum ve bu yöntem tam olarak bunu sağlıyordu. Gereksiz bağımlılıklardan kaçınarak sadece ihtiyacım olanı yapmak, yazılım geliştirme sürecinde her zaman en sağlıklı yoldur.

Farklı kütüphaneler denemek yerine neden bu yöntemi seçtiğimi açıklamam gerekirse, sadelik her zaman kazanır. Örneğin, Selenium veya Playwright gibi araçlar kullanarak tarayıcı simülasyonu yapmak, sistem kaynaklarını gereksiz yere tüketir ve işlem süresini ciddi oranda artırır. Oysa sadece bir başlık eklemek, ağ trafiğinde hiçbir ek yük oluşturmaz ve sunucuyla doğrudan iletişimi korur. Bu yaklaşım, API ile olan etkileşimi en saf ve hızlı haliyle tutmamı sağladı. Karmaşık araçlara başvurmadan önce, HTTP protokolünün sunduğu temel özellikleri doğru yapılandırmak çoğu zaman yeterlidir.

gorsel

Bundan sonra ne yapmalı

Bundan sonra bir API ile çalışırken ilk yapacağım şey, sunucunun benden ne beklediğini anlamak olacak. Bir hata aldığımda hemen kodumu değiştirmek yerine, önce basit hipotezler kuracağım. Ucuz hipotezler, yani başlık, zaman aşımı veya kodlama gibi basit şeyler her zaman ilk sırada olmalı. Eğer bir hata ile karşılaşırsan, önce değişkenleri tek tek izole et. Hepsiyle aynı anda oynama.

API dokümantasyonunu daha dikkatli okumak ve istekleri bir ağ izleme aracıyla incelemek, bu tür sorunları daha hızlı çözmeni sağlar. Kendi hatalarından ders çıkarmak, bir sonraki projede aynı vakit kaybını yaşamamanı sağlar. Şimdi bu öğrendiklerini al ve kendi projelerinde uygula. Bir dahaki sefere bir 403 hatası aldığında panik yapma, sadece kimliğini düzgün tanıtıp tanıtmadığını kontrol et. Yazılım geliştirmek bir yapboz gibi, bazen sadece bir parçanın eksik olduğunu fark etmen yeterli.

Top comments (0)