
![]()
Giriş: Neden HTTP İstemcileri Bu Kadar Önemli?
Veri mühendisliği (data engineering) dünyasında günümüzün hemen her veri akış hattı (data pipeline) bir noktada dış API’larla konuşmak zorunda kalıyor. İster bir REST API’den veri çekiyor olalım, ister bir webhook (web kancası) dinliyor olalım, isterse de mikroservisler (microservices) arasında veri taşıyor olalım — HTTP istekleri (HTTP requests) işimizin tam göbeğinde. Peki Python’da bu iş için doğru aracı seçiyor muyuz? Yoksa alışkanlıktan import requests yazıp geçiyor muyuz?
Bu yazıda üç büyük Python HTTP istemci kütüphanesini inceleyeceğiz: Requests, AIOHTTP ve HTTPX. Her birinin güçlü ve zayıf yanlarına bakacağız, performans (performance) karşılaştırmaları yapacağız ve özellikle veri mühendisliği bağlamında hangisinin ne zaman tercih edilmesi gerektiğini tartışacağız.
1. Requests: Herkesin Tanıdığı Klasik
Python ekosisteminde HTTP istekleri dendiğinde akla gelen ilk kütüphane (library) hiç şüphesiz Requests’tir. Öyle yaygın kullanılıyor ki, birçok geliştirici onu standart kütüphanenin (standard library) bir parçası sanıyor [1]. r = requests.get(...) yazmak adeta kas hafızasına işlenmiş durumda.
Requests’in en büyük kozu sadelik (simplicity). Bir GET isteği göndermek için tek satır yeterli: requests.get(url) ve bitti. Başlıklar (headers), zaman aşımı (timeout), çerezler (cookies) gibi seçenekleri de kolayca ekleyebiliyoruz [2]. Ancak bu sadeliğin bir bedeli var.
Requests’in Temel Sorunu: Senkron (Synchronous) Yapı
Requests tamamen senkron (synchronous) çalışır. Bu ne demek? Bir istek gönderdiğimizde, yanıt gelene kadar programımız tamamen bloke olur (blocking). Eğer ardı ardına dört farklı API’ye istek gönderiyorsak, her biri sırayla beklemek zorundadır — biri bitmeden diğeri başlamaz [3]. Bir veri akış hattında düşünün: 50 farklı kaynaktan veri çekiyorsunuz ve her biri ortalama 200 milisaniye sürüyor. Ardışık (sequential) çalıştırdığınızda toplam süre 10 saniye. Asenkron (asynchronous) bir yaklaşımla bu süre en yavaş yanıtın süresi kadarına düşebilir.
Üstelik Requests varsayılan (default) kullanımında her istek için yeni bir bağlantı (connection) oluşturur. Bu da performans açısından ciddi bir kayıp demek. Çözüm olarak oturum (Session) nesnesi kullanabiliriz — Requests’in bağlantı havuzlama (connection pooling) mekanizması bu şekilde devreye girer ve aynı sunucuya (server) yapılan isteklerde mevcut TCP bağlantıları yeniden kullanılır. Bu basit değişiklik bile performansı neredeyse ikiye katlayabilir [4].
Requests ile Oturum (Session) Kullanımı
Oturum kullanımı, Requests’in güçlü ama az bilinen bir özelliğidir. Bir oturum nesnesi oluşturduğumuzda, bu nesne bizim için bir bağlantı havuzu (connection pool) yönetir. Böylece her istekte yeniden TCP el sıkışması (TCP handshake) yapılmasına gerek kalmaz. Testlerde oturumsuz kullanımda yaklaşık 1.6 saniye süren işlemler, oturum ile 0.8 saniyeye kadar düşebiliyor [5]. Ancak asenkron (asynchronous) çalışma desteği yok. Bu da bizi diğer seçeneklere yönlendiriyor.
Requests ayrıca HTTP/2 desteği sunmuyor ve urllib3 üzerine inşa edilmiş durumda [6]. Modern API’ların birçoğu HTTP/2 protokolünü desteklediğinden, bu özelliğin eksikliği özellikle yüksek veri hacimli (high-volume) senaryolarda hissediliyor.
2. AIOHTTP: Performans Odaklı Asenkron Dev
AIOHTTP, Python’ın asyncio çerçevesi (framework) üzerine inşa edilmiş, tamamen asenkron (asynchronous) bir HTTP istemcisidir [7]. 2014 yılından bu yana varlığını sürdüren AIOHTTP, asyncio’yu tam anlamıyla kucaklayan ilk kütüphanelerden biridir. Requests basitliğe odaklanırken, AIOHTTP performansa odaklanır [8].
AIOHTTP’un varsayılan davranışı zaten bir oturum (session) oluşturmayı gerektirir — yani bağlantı havuzlama (connection pooling) işin doğasında var. Bu, Requests’teki gibi sonradan keşfedilen bir özellik değil, mimarinin (architecture) temelinde yer alır.
AIOHTTP’un Güçlü Yanları
Performans testlerinde AIOHTTP, Requests’e göre yaklaşık 10 kat, HTTPX’e göre ise yaklaşık yüzde 50 daha hızlı sonuçlar üretebiliyor [9]. Saniyede 241’den fazla istek işleyebildiği raporlanmış testlerde, AIOHTTP performans konusunda kendi liginde yer alıyor.
Bunun yanı sıra AIOHTTP sadece bir istemci (client) değil, aynı zamanda bir sunucu (server) olarak da çalışabilir. WebSocket desteği, ara yazılım kancaları (middleware hooks) ve oturum yönetimi (session handling) gibi özellikler de sunuyor [10]. Veri mühendisliği perspektifinden bakıldığında, binlerce eşzamanlı (concurrent) HTTP çağrısı yapmanız gereken senaryolarda AIOHTTP en ideal seçim olarak öne çıkıyor.
British Geological Survey ekibi, AIOHTTP ve asyncio kullanarak 27.000’den fazla API çağrısının süresini 2.5 saatten yaklaşık 7 dakikaya düşürdüklerini bildirmiştir [11]. Bu, veri mühendisliğinde asenkron programlamanın (asynchronous programming) somut etkisini gösteren çarpıcı bir örnek.
AIOHTTP’un Dezavantajları
AIOHTTP’un en büyük dezavantajı öğrenme eğrisi (learning curve). Tamamen asenkron olduğu için senkron (synchronous) bir mod sunmuyor [12]. Her işlem için async/await yapısı kullanmamız gerekiyor ve bağlam yöneticileri (context managers) ile çalışmak kodu biraz daha karmaşık hale getiriyor. Basit bir GET isteği bile birden fazla iç içe async with bloku gerektiriyor.
Ayrıca HTTP/2 desteği bulunmuyor [13]. Modern API’larda HTTP/2’nin sağladığı çoğullama (multiplexing), başlık sıkıştırma (header compression) ve akış önceliklendirme (stream prioritization) gibi avantajlardan yararlanamıyoruz. Eğer HTTP/2 sizin için kritik bir gereksinim değilse bu bir sorun olmayabilir, ama modern veri altyapılarında (data infrastructure) giderek daha fazla karşımıza çıkıyor.
3. HTTPX: İki Dünyanın En İyisi
HTTPX, Django REST Framework’ün yaratıcısı Tom Christie tarafından geliştirilmiş, yeni nesil bir HTTP istemcisidir [14]. HTTPX’in en dikkat çekici özelliği, hem senkron (synchronous) hem de asenkron (asynchronous) modda çalışabilmesi. Yani Requests’in basitliğini ve AIOHTTP’un performansını tek bir kütüphanede birleştiriyor [15].
HTTPX’in API’si Requests ile neredeyse tamamen uyumlu (compatible). Kodunuzda sadece import requests satırını import httpx ile değiştirmeniz çoğu durumda yeterli olacaktır [16]. Bu geçiş kolaylığı, mevcut kod tabanlarını (codebase) modernize etmek isteyen ekipler için büyük bir avantaj.
HTTPX’in Öne Çıkan Özellikleri
HTTPX’in sunduğu en önemli özellikler şunlardır: hem senkron hem asenkron destek (sync and async support), yerel HTTP/2 desteği (native HTTP/2 support), tam tür açıklamaları (full type annotations), bağlantı havuzlama (connection pooling) ve akış yanıtları (streaming responses) [17]. HTTP/2 desteği sayesinde çoğullama (multiplexing) — yani tek bir TCP bağlantısı üzerinden birden fazla istek ve yanıt gönderme — mümkün hale geliyor [18].
Bağlantı havuzlama için HTTPX bir İstemci (Client) nesnesi kullanır. Requests’teki Session nesnesine benzer şekilde, Client nesnesi bağlantıları yeniden kullanarak gecikmeyi (latency) azaltır, işlemci (CPU) kullanımını düşürür ve ağ tıkanıklığını (network congestion) önler [19]. Varsayılan olarak en fazla 100 bağlantı ve 20 canlı bağlantı (keep-alive connections) destekleniyor [20].
HTTPX ile Asenkron (Async) Çalışma
HTTPX’in asenkron tarafı AsyncClient ile devreye girer. Normal Client ile senkron, AsyncClient ile asenkron çalışabiliriz — aynı projede her iki modu birlikte kullanmak bile mümkün [21]. Bu esneklik, özellikle mevcut bir senkron kod tabanını kademeli olarak asenkrona geçirmek isteyenler için çok değerli.
HTTPX dokümantasyonunda (documentation) önemli bir uyarı var: bağlantı havuzlamanın en verimli şekilde çalışması için birden fazla istemci örneği (client instance) oluşturmaktan kaçınmamız gerekiyor. Özellikle bir döngü (“hot loop”) içinde sürekli yeni istemci oluşturmak, havuzlamanın avantajlarını ortadan kaldırır [22]. Tek bir istemciyi ya da kapsamlı (scoped) bir istemciyi tüm işlemlerde paylaşmak en doğru yaklaşım.
4. Eşzamanlı İstekler (Concurrent Requests): Asıl Fark Burada
Veri mühendisliğinde asıl performans farkı, eşzamanlı (concurrent) isteklerde ortaya çıkıyor. Senkron (synchronous) dört API çağrısı düşünün: her biri 500 milisaniye sürüyorsa toplam 2 saniye bekleriz. Eşzamanlı (concurrent) çalıştırırsak bu süre sadece en uzun isteğin süresi kadar olur — yani yaklaşık 500 milisaniye [23].
Python’da eşzamanlı istekleri yönetmek için asyncio.gather() fonksiyonu (function) kullanılır. Bu fonksiyon birden fazla eşyordamı (coroutine) alır, bunları görevlere (tasks) dönüştürür, eşzamanlı çalıştırır ve tüm sonuçları tek bir listede toplar [24]. HTTPX ile bu işlem oldukça sezgisel (intuitive) bir şekilde yapılabilir — AsyncClient ile birlikte asyncio.gather() kullanarak tüm isteklerimizi aynı anda gönderebiliriz.
Testlerde oturumsuz Requests ile yaklaşık 1.6–2 saniye süren işlemler, HTTPX AsyncClient ve eşzamanlı isteklerle 0.4–0.7 saniyeye kadar düşebiliyor [25]. Eşzamanlı istek sayısı arttıkça bu kazanım katlanarak büyüyor.
Hız Sınırlama (Rate Limiting) Konusunda Dikkat!
Eşzamanlı (concurrent) isteklerle çalışırken dikkat etmemiz gereken kritik bir konu var: hız sınırlama (rate limiting). Bir API’ye aynı anda yüzlerce istek gönderdiğimizde, API sağlayıcısının koyduğu sınırlara takılabiliriz [26]. Bu durumu yönetmek için asyncio.Semaphore kullanarak eşzamanlı görev sayısını (concurrent task count) kontrol altında tutabiliriz [27].
Örneğin, aynı anda en fazla 10 istek göndermek istiyorsak, bir semafor (Semaphore) oluşturup her görevi bu semafor üzerinden geçirebiliriz. Bu sayede API sınırlarını aşmadan eşzamanlılığın (concurrency) avantajlarından yararlanabiliriz. Veri mühendisleri olarak bu dengeyi iyi kurmamız gerekiyor: çok agresif olursak 429 (Too Many Requests) hataları alırız, çok muhafazakâr olursak performans kazanımımız sınırlı kalır.
5. Karşılaştırma Tablosu: Requests vs AIOHTTP vs HTTPX
Şimdi üç kütüphaneyi temel kriterlere göre yan yana koyalım:
| Özellik | Requests | AIOHTTP | HTTPX |
|---|---|---|---|
| Senkron (Sync) Destek | ✅ | ❌ | ✅ |
| Asenkron (Async) Destek | ❌ | ✅ | ✅ |
| HTTP/2 Desteği | ❌ | ❌ | ✅ |
| Bağlantı Havuzlama (Connection Pooling) | Oturum ile | Varsayılan | Client ile |
| Performans Sıralaması | 3. | 1. | 2. |
| Öğrenme Kolaylığı | Çok Kolay | Zor | Kolay |
| Lisans (License) | Apache 2.0 | Apache 2.0 | BSD 3-Clause |
| WebSocket Desteği | ❌ | ✅ | ❌ |
| Tür Açıklamaları (Type Annotations) | Kısmi | Kısmi | Tam |
Requests sadece senkron çalışırken, AIOHTTP yalnızca asenkron, HTTPX ise her iki modu da destekliyor [28]. HTTP/2 desteği yalnızca HTTPX’te mevcut [29]. Performans sıralamasında AIOHTTP birinci, HTTPX ikinci ve Requests üçüncü sırada yer alıyor [30].
Lisans (license) açısından da kısa bir bilgi verelim: Requests ve AIOHTTP Apache 2.0, HTTPX ise BSD 3-Clause lisansı altında dağıtılıyor. Her ikisi de ticari kullanıma (commercial use) izin veriyor. Apache 2.0 patent hakları (patent rights) konusunda biraz daha fazla yasal koruma sağlıyor, ancak pratikte çoğu proje için bu fark ihmal edilebilir düzeyde.
6. Veri Mühendisleri İçin Pratik Senaryolar
Senaryo 1: Basit ETL Betiği (Simple ETL Script)
Eğer tek bir API’den günde bir kez veri çeken basit bir ETL betiğiniz (script) varsa ve performans kritik değilse, Requests gayet yeterli. Oturum (Session) kullanmayı unutmayın yeter. Kod basit, okunur ve bakımı kolay olacaktır.
Senaryo 2: Çoklu API Entegrasyonu (Multi-API Integration)
Birden fazla API’dan eşzamanlı (concurrent) veri çekmeniz gerekiyorsa — örneğin hem bir ödeme API’sinden hem bir CRM API’sinden hem de bir analitik API’sinden — HTTPX’in AsyncClient‘ı ideal. Hem Requests API’siyle uyumlu olduğu için geçiş kolay, hem de eşzamanlı isteklerle performans artışı elde edebilirsiniz.
Senaryo 3: Yüksek Hacimli Veri Toplama (High-Volume Data Collection)
Binlerce eşzamanlı (concurrent) bağlantı yönetmeniz gereken senaryolarda — örneğin büyük ölçekli web kazıma (web scraping) veya gerçek zamanlı (real-time) veri akışları — AIOHTTP en uygun seçim. Olay döngüsü (event loop), eşyordam (coroutine) ve bağlantı yeniden kullanım (connection reuse) üzerine kurulu mimarisi, bu tür ağır yükler için optimize edilmiş durumda.
Senaryo 4: Kademeli Göç (Gradual Migration)
Mevcut kod tabanınızda zaten Requests kullanıyorsanız ve performansı artırmak istiyorsanız, HTTPX en mantıklı geçiş yoludur. API uyumluluğu sayesinde önce senkron (synchronous) modda başlayıp, ihtiyaç duydukça belirli modülleri asenkrona (asynchronous) taşıyabilirsiniz. Tüm kodu bir gecede değiştirmek zorunda kalmaz, adım adım ilerleyebilirsiniz.
7. En İyi Uygulamalar (Best Practices)
Hangi kütüphaneyi kullanırsanız kullanın, bazı temel ilkeler değişmez:
Mutlaka bağlantı havuzlama (connection pooling) kullanın. Requests’te Session, HTTPX’te Client veya AsyncClient, AIOHTTP’da ClientSession nesneleri bu işi görür. Her istekte yeni bağlantı açmak gereksiz gecikme (latency) yaratır.
Bağımsız istekleri (independent requests) mümkün olduğunca eşzamanlı (concurrent) gönderin. Eğer bir isteğin sonucu diğerinin girdisi değilse, bunları ardışık (sequential) göndermek için hiçbir neden yok.
Zaman aşımı (timeout) değerlerini her zaman belirleyin. Bir API yanıt vermezse, veri akış hattınız (pipeline) sonsuza kadar beklemek zorunda kalmamalı.
Hata yönetimi (error handling) stratejinizi belirleyin. Özellikle asyncio.gather() kullanırken return_exceptions=True parametresi ile hataların diğer görevleri durdurmasını engelleyebilirsiniz.
Hız sınırlama (rate limiting) stratejinizi baştan planlayın. Semafor (Semaphore) veya benzeri mekanizmalarla eşzamanlı (concurrent) görev sayısını kontrol altında tutun.
8. Peki Hangisini Seçelim?
GitHub yıldız sayısına bakıldığında Requests açık ara önde, AIOHTTP ikinci sırada ve HTTPX en az yıldıza sahip olanı. Ancak popülerlik her zaman en iyi seçimi göstermez. HTTPX, üç kütüphanenin sunduğu avantajları tek çatı altında toplayan modern bir çözüm. Requests’in basitliğini, AIOHTTP’un asenkron güçlüğünü ve üzerine HTTP/2 desteğini bir arada sunuyor.
Mid ve senior veri mühendisleri olarak önerim şu: yeni projeler için HTTPX’i varsayılan seçeneğiniz yapın. Senkron başlayıp ihtiyaç duydukça asenkrona geçebilirsiniz. Mevcut Requests kodlarını kademeli olarak HTTPX’e taşıyın — API uyumluluğu sayesinde bu geçiş ağrısız olacaktır. Eğer binlerce eşzamanlı (concurrent) bağlantının olduğu, performansın her şeyden önemli olduğu senaryolardaysanız, AIOHTTP sizin silahınız olsun.
Kısacası: basitlik istiyorsanız Requests, esneklik istiyorsanız HTTPX, mutlak performans istiyorsanız AIOHTTP. Ama eğer tek bir seçim yapmak zorundayım derseniz — HTTPX. GitHub’da en az yıldıza sahip olanı seçmek bazen en doğru karar olabiliyor.
Sonuç
Python’da HTTP istemci kütüphaneleri seçimi, veri akış hatlarımızın (data pipelines) performansını doğrudan etkileyen kritik bir mühendislik kararı. Bu yazıda Requests’in sadeliğini, AIOHTTP’un çiğ performansını ve HTTPX’in dengeli yaklaşımını derinlemesine inceledik.
Önemli olan şey, projenizin gereksinimlerini (requirements) doğru analiz edip ona göre seçim yapmak. Her üç kütüphane de kendi alanında mükemmel — mesele doğru aracı doğru iş için kullanmak. Bağlantı havuzlama, eşzamanlı istekler ve hız sınırlama gibi kavramları içselleştirdiğinizde, hangi kütüphaneyi kullanırsanız kullanın veri boru hatlarınızın performansını önemli ölçüde artırabilirsiniz.
Bir sonraki yazıda görüşmek üzere!
Veri mühendisliği alanında harika bir kariyer için en güzel eğitim: VBO Data Engineering Bootcamp
Kaynaklar
[1] Speakeasy – Python HTTP Clients: Requests vs. HTTPX vs. AIOHTTP. https://www.speakeasy.com/blog/python-http-clients-requests-vs-httpx-vs-aiohttp
[2] Oxylabs – HTTPX vs Requests vs AIOHTTP. https://oxylabs.io/blog/httpx-vs-requests-vs-aiohttp
[3] Medium – Jai Kishan – Requests vs Aiohttp vs HTTPX: Choosing the right Python HTTP Libraries. https://medium.com/@jkishan421/requests-vs-aiohttp-vs-httpx-choosing-the-right-python-http-libraries-8a06373e9744
[4] ArjanCodes (YouTube) – HTTP Requests in Python: requests, aiohttp, httpx. Video transcript – source material.
[5] ArjanCodes (YouTube) – Session-based performance benchmarks. Video transcript – source material.
[6] IPRoyal – HTTPX vs AIOHTTP vs Requests: Which to Choose? https://iproyal.com/blog/httpx-vs-aiohttp-vs-requests/
[7] Speakeasy – AIOHTTP: Purely asynchronous design. https://www.speakeasy.com/blog/python-http-clients-requests-vs-httpx-vs-aiohttp
[8] Oxylabs – AIOHTTP performance optimization approach. https://oxylabs.io/blog/httpx-vs-requests-vs-aiohttp
[9] Bright Data – Requests vs. HTTPX vs. AIOHTTP: Which One to Choose? https://brightdata.com/blog/web-data/requests-vs-httpx-vs-aiohttp
[10] ProxyWing – HTTPX vs Requests vs AIOHTTP — Feature and Performance Comparison. https://proxywing.com/blog/httpx-vs-requests-vs-aiohttp-feature-performance-comparison-guide
[11] British Geological Survey – Speeding up ETLHelper’s API transfers with asyncio. https://britishgeologicalsurvey.github.io/open-source/async-etlhelper-api-transfer/
[12] DEV Community – jaironlanda – httpx vs aiohttp: A Simple Comparison for Beginners. https://dev.to/jaironlanda/httpx-vs-aiohttp-a-simple-comparison-for-beginners-o2o
[13] Oxylabs – AIOHTTP does not support HTTP/2. https://oxylabs.io/blog/httpx-vs-requests-vs-aiohttp
[14] Speakeasy – HTTPX created by Tom Christie. https://www.speakeasy.com/blog/python-http-clients-requests-vs-httpx-vs-aiohttp
[15] Medium – Jai Kishan – HTTPX combines simplicity and async performance. https://medium.com/@jkishan421/requests-vs-aiohttp-vs-httpx-choosing-the-right-python-http-libraries-8a06373e9744
[16] GitHub – encode/httpx – HTTPX: A next generation HTTP client for Python. https://github.com/encode/httpx
[17] Better Stack – Getting Started with HTTPX: Python’s Modern HTTP Client. https://betterstack.com/community/guides/scaling-python/httpx-explained/
[18] HTTPX Documentation – HTTP/2 Support. https://www.python-httpx.org/http2/
[19] HTTPX Documentation – Clients – Connection Pooling. https://www.python-httpx.org/advanced/clients/
[20] HTTPX Documentation – Resource Limits. https://www.python-httpx.org/advanced/resource-limits/
[21] HTTPX Documentation – Async Support. https://www.python-httpx.org/async/
[22] HTTPX Documentation – Connection pooling best practices. https://www.python-httpx.org/async/
[23] ShanéChang – Running Parallel Operations with Asyncio Gather. https://shanechang.com/p/python-asyncio-gather-explained/
[24] Python Tutorial – Python asyncio.gather(). https://www.pythontutorial.net/python-concurrency/python-asyncio-gather/
[25] ArjanCodes (YouTube) – Concurrent requests performance benchmarks. Video transcript – source material.
[26] ArjanCodes (YouTube) – Rate limiting considerations. Video transcript – source material.
[27] Instructor – Mastering Python asyncio.gather and asyncio.as_completed. https://python.useinstructor.com/blog/2023/11/13/learn-async/
[28] DEV Community – Leapcell – Comparing requests, aiohttp, and httpx. https://dev.to/leapcell/comparing-requests-aiohttp-and-httpx-which-http-client-should-you-use-3784
[29] HTTPX Official Site – HTTPX Features Overview. https://www.python-httpx.org/
[30] Bright Data – Performance benchmarks: AIOHTTP vs HTTPX vs Requests. https://brightdata.com/blog/web-data/requests-vs-httpx-vs-aiohttp