REST API'lerde sayfalama (pagination), büyük veri kümelerini yönetilebilir parçalara bölmek için kritik bir desendir. Geleneksel offset/limit yaklaşımı basit olsa da, yüksek eşzamanlılık ve sık veri değişiklikleri olan sistemlerde tutarlılık sorunlarına yol açar. Cursor-based pagination (imleç tabanlı sayfalama), bu sorunları çözmek için daha sağlam bir alternatiftir. Bu yazıda cursor pagination'ın temel prensiplerini, pratik uygulama adımlarını ve yaygın hatalardan kaçınmak için bir kontrol listesini bulacaksınız.
Neden Cursor-Based Pagination?
Offset/limit, her sayfada bir önceki sayfadaki verilerin değişmemesini varsayar. Ancak gerçek dünyada yeni kayıtlar eklenebilir veya mevcut kayıtlar silinebilir. Bu durumda kullanıcı aynı kaydı iki kez görebilir veya bir kaydı atlayabilir. Cursor-based pagination ise sabit bir referans noktasına (örneğin, bir kaydın benzersiz ID'si veya zaman damgası) dayanarak sayfalar arasında gezinir. Bu sayede veri değişikliklerinden etkilenmez ve her zaman tutarlı sonuçlar döndürür.
Ayrıca, performans açısından offset/limit büyük ofset değerlerinde veritabanında full scan'e yol açabilirken, cursor-based sorgular indeks kullanarak hızlıca ilgili konuma atlar. Bu da özellikle büyük veri kümelerinde belirgin bir fark yaratır.
Uygulama Adımları
1. Uygun Bir Cursor Alanı Seçin
Cursor olarak kullanılacak alan şu özellikleri taşımalıdır:
- Benzersiz olmalı (örneğin, birincil anahtar veya UUID)
- Değişmez olmalı (güncellenmemeli)
- Sıralanabilir olmalı (genellikle artan veya azalan bir sıra)
- İndekslenmiş olmalı (performans için)
En yaygın seçenekler: id (sıralı veya UUID), created_at zaman damgası. Zaman damgası kullanıyorsanız, aynı anda birden fazla kaydın aynı zaman damgasına sahip olma ihtimaline karşı yedek bir benzersiz alanla birleştirin (örneğin created_at + id).
2. API Parametrelerini Tasarlayın
Standart parametreler:
cursor: Bir sonraki sayfanın başlayacağı noktayı belirten değer (genellikle base64 kodlanmış veya ham)limit: Sayfa başına öğe sayısı (maksimum bir değerle sınırlayın, örn. 100)- Opsiyonel:
direction(next/prev) veyasort_order(asc/desc)
Yanıt yapısı örneği:
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6MTB9",
"has_more": true
}
}Cursor değerini istemciden alırken, sunucu bu değeri çözümleyip ilgili kaydın bulunduğu konumu belirler. Önemli: Cursor'ı kullanıcının değiştirebileceğini varsayın ve geçerliliğini kontrol edin.
3. Sorguyu Oluşturun
Veritabanı sorgunuzda cursor alanını bir WHERE koşulunda kullanın. Örneğin, azalan sırada sıralanmış kayıtlarda bir sonraki sayfa için:
SELECT * FROM posts WHERE id < @cursor ORDER BY id DESC LIMIT @limit
İlk sayfa için cursor parametresi atlanabilir veya NULL gönderilebilir. Sunucu ilk sayfayı döndürürken en son kaydın cursor'ını yanıta ekler.
4. Hata Yönetimi ve Geçersiz Cursor
Cursor değeri geçersiz, bozulmuş veya silinmiş bir kaydı işaret ediyorsa sunucu uygun bir hata mesajı döndürmelidir. Örneğin, 400 Bad Request ile {"error":"Invalid cursor"}. Ayrıca, cursor'ın süresinin dolması gibi bir konsept uygulayabilirsiniz (isteğe bağlı).
Kontrol Listesi (Checklist)
- Cursor alanı indekslenmiş mi? İndeks yoksa performans düşer.
- Cursor değeri güvenli bir şekilde kodlanmış mı? Base64 kullanmak yaygındır ancak mutlaka doğrulayın.
- Hem ileri hem geri sayfalama destekleniyor mu? Çoğu durumda sadece ileri yeterlidir, ancak gereksinimleri kontrol edin.
- Limit için üst sınır belirlenmiş mi? Aşırı büyük limitler sunucuyu zorlayabilir.
- Yanıtta has_more alanı var mı? Kullanıcı daha fazla veri olduğunu bilsin.
- Cursor null olduğunda ilk sayfa dönüyor mu? İlk sayfa için cursor göndermeyen istemciler düzgün çalışmalı.
- Silinmiş kayıtlar cursor olarak kullanılıyor mu? Silinen kayıtlar referans olarak kullanılmamalı, yoksa hata alırsınız.
- Sıralama düzeni değiştirilebilir mi? İzin veriyorsanız, cursor değerinin sıralama bilgisini de içermesi gerekebilir.
Sık Yapılan Hatalar
- Offset mantığıyla karıştırmak: Cursor, sayfa numarası değil, bir referans noktasıdır. İstemciler cursor'ı bir anahtar gibi saklamalı, sayfa numarası beklememelidir.
- Cursor'ı şifrelememek: Base64 yeterlidir; şifreleme gerekli değildir ancak kurcalamayı önlemek isterseniz HMAC eklenebilir.
- Benzersiz olmayan cursor alanı kullanmak: Örneğin sadece
created_atkullanılırsa aynı anda eklenen kayıtlarda atlama veya tekrar olabilir. - Tüm veriyi döndürmek: Her zaman limit uygulayın; sonsuz döngüye girilmesini engelleyin.
Performans İpuçları
Cursor-based pagination, özellikle büyük veri kümelerinde offset'e göre çok daha hızlıdır. Bununla birlikte, her sorguda ek bir indeks taraması yapılır. İndeksinizin kapsamlı olduğundan emin olun. Ayrıca, API versiyonlama stratejileri ile birlikte kullanıldığında, eski istemcilerin cursor formatını değiştirmemesi için versiyonlama uygulayabilirsiniz.
Başka bir performans iyileştirmesi ise sayfalama sonuçlarını önbelleğe almaktır. Ancak cursor tabanlı sayfalamada her sayfanın kendine özgü bir cursor'ı olduğu için önbellekleme daha karmaşıktır. Yine de sık talep edilen sıralamalar için önbellekleme düşünülebilir.
Sonuç
Cursor-based pagination, tutarlılık ve performans gerektiren REST API'ler için tercih edilmesi gereken bir desendir. Yukarıdaki adımları ve kontrol listesini takip ederek uygulamanıza sağlam bir sayfalama katmanı ekleyebilirsiniz. Daha fazla bilgi için API rate limiting algoritmaları hakkındaki yazımıza da göz atabilirsiniz.
Sık Sorulan Sorular
Cursor-based pagination ile offset-based arasındaki temel fark nedir?
Offset-based pagination, sayfa numarasına göre atlama yaparken veri değişikliklerinden etkilenir. Cursor-based ise sabit bir referans noktası kullanarak tutarlı ve performanslı sonuçlar döndürür.
Cursor olarak hangi alanı kullanmalıyım?
Benzersiz, değişmez ve sıralanabilir bir alan seçin. En yaygın seçenekler birincil anahtar (id) veya created_at + id kombinasyonudur.
Cursor değerini nasıl güvenli hale getirebilirim?
Genellikle base64 kodlama yeterlidir. Kurcalamayı önlemek isterseniz, cursor'a HMAC imzası ekleyebilirsiniz.
Geçersiz bir cursor gönderilirse ne olur?
Sunucu 400 Bad Request hatası döndürmeli ve geçersiz cursor olduğunu belirten bir hata mesajı içermelidir.
Cursor-based pagination her durumda offset'ten iyi midir?
Genellikle evet, özellikle büyük veri kümelerinde ve sık güncelleme yapılan sistemlerde. Ancak kullanıcıların rastgele sayfalara atlaması gerekiyorsa offset daha uygun olabilir.






