Axios İpuçları #4: localForage ile HTTP Yanıtlarını IndexedDB’de Önbelleklemek

Tuğsan Ünlü
4 min readMar 11, 2022

Axios serisindeki bir önceki yazı: Axios İpuçları #3: LRU Cache ile HTTP Yanıtlarını Önbelleklemek

Motivasyon

Daha önce, Axios istemcisiyle yapılan HTTP isteklerinin yanıtlarını istemci üzerinde önbelleklemeye dair bir yazı yazmıştım. O yazıda bahsettiğim yöntem, LRU cache algoritmasını kullanmakta ve HTTP yanıtlarını session storage’da saklamaktaydı.

Gerek session storage’da en fazla 5MB veri saklanabilmesi gerek de aktif tarayıcı sekmesi kapandığında session storage’daki verilerin sıfırlanması hasebiyle bu yöntem kısıtlı kullanım senaryolarında geçerliydi. SPA ve mobil uygulamalar gibi, istemci üzerinde render edilip (CSR) aynı oturumda hayatına devam eden uygulamalar için iyi bir çözüm sunarken sunucuda render edilen (SSR) ve/veya daha büyük boyutlu verilerin önbelleklenmesi gereken uygulamalarda yetersiz kalıyordu.

Bu yazıda buna alternatif olarak Axios ile IndexedDB üzerinde nasıl önbellekleme yapılacağından bahsedeceğim.

IndexedDB

IndexedDB, istemci cihazlarında anahtar-değer (key-value pair) çiftleri formatında veri saklamaya olanak tanıyan bir web API’ı. Başka bir deyişle tarayıcı içerisinde tutulan bir NoSQL veritabanı aslında. Cookie, local storage, session storage gibi diğer çözümlerin aksine sabit bir veri saklama kapasitesi yok. İstemci diskindeki boş alan ve kullanılan tarayıcının yeteneklerine göre değişkenlik gösteriyor. İstisnalar olmakla birlikte kabaca istemci diskindeki boş alanın %50'si kadar bir depolama alanını IndexedDB kullanabiliyor. Bu alan dolduğunda ise en az kullanılandan başlanarak önbellekler birer birer siliniyor.

localForage

IndexedDB’nin tarayıcıda veri saklayabilen diğer yöntemlerden bir farkı da asenkron olarak çalışması. Örneğin local storage’a yapılan okuma ve yazma işlemleri senkrondur. Geliştirdiğimiz uygulama içerisinde local storage’a bir veri yazıyoruz diyelim. Bu veri yazma işlemi tamamlanana kadar uygulama geçici olarak bloklanır ve yazma işlemi tamamlandığında kaldığı yerden çalışmaya devam eder. Bunu o kadar hızlı bir şekilde yapar ki ne uygulamada bir aksama yaşanır ne de son kullanıcı duraklamayı fark eder.

localForage

Fakat IndexedDB büyük boyuttaki verileri bir veritabanı gibi yönettiğinden doğası gereği farklıdır. Veritabanı oluşturmak, veritabanına bağlanmak, veri yazmak, veri okumak gibi işlemler API’ın sağladığı interface’ler aracılığıyla asenkron olarak yapılır. Fakat bu da beraberinde implementasyon zorluklarını getirir. Bu nedenle MDN dâhil olmak üzere birçok kaynak, IndexedDB operasyonlarını daha pratik kütüphaneler aracılığıyla yapmayı önerir. İsminden anlaşılacağı gibi, IndexedDB’i local storage kolaylığında kullanmayı amaçlayan localForage, bu kütüphanelerden en yaygın olanı. Kullanılan tarayıcıların yeteneklerine göre muhtelif polyfill çözümlerini de içeriyor.

Axios ile localForage Kullanımı

Sıra geldi Axios, IndexedDB ve localForage üçlüsünü birlikte kullanmaya. İlk olarak bağımlılıkları kuralım.

NPM ile bağımlıkların kurulması

Akabinde localforage için bir store oluşturalım. Bu store içerisinde localforage instance’ı yaratıyoruz. IndexedDB için kullanacağımız veritabanı adını ve driver bilgisini bu instance içerisinde tanımlıyoruz. Hemen yukarıda bahsettiğim polyfill çözümü burada karşımıza çıkıyor. Driver seçimi için birincil olarak IndexedDB’i, ikincil olarak ise local storage’ı belirtiyoruz. Kullanıcılar, IndexedDB’nin desteklenmediği bir tarayıcı kullanıyorlarsa uygulamanın akışı hiç bozulmadan veritabanı olarak local storage kullanılmaya başlanıyor. Son olarak HTTP yanıtlarının ne kadar süreyle önbellekleneceğini belirtip yarattığımız localforage instance’ının Axios ile eşleşmesini axios cache adapter marifetiyle sağlıyoruz.

localforage için store oluşturulması

Uygulama içerisinde, her tıklandığında GitHub’ın public API’larından istenilen kullanıcı bilgilerini getiren basit bir buton olduğunu varsayalım. Normal şartlarda GitHub API’ına yapacağımız HTTP isteğini, az önce oluşturduğumuz localforage instance’ı ile sarmalıyoruz. Bu sayede GitHub’a yapılacak HTTP istekleri için bir ara katman oluşturuyoruz. Böylece GitHub’a yapılacak tüm istekler ilk olarak localforage üzerinden geçecek ve isteğin yapılıp yapılmayacağına ve hangi yanıtın verileceğine localforage karar verecek.

http isteğinin localforage store’u ile sarmalanması

Uygulamayı çalıştıralım ve DevTools üzerinden izleyelim.

Butona tıklayıp DevTools’daki Network sekmesine baktığımızda HTTP isteğinin GitHub sunucularına yapıldığını ve karşılığında bir yanıt alındığını görüyoruz.

ilk http isteği

Akabinde Application sekmesindeki Storage > IndexedDB menüsüne baktığımızda githubCacheDB isimli bir veritabanı görüyoruz. Bu veritabanında anahtar (key) olarak seslendiğimiz API ucu, değer (value) olarak da bir obje görüyoruz. Obje içerisinde ise GitHub’dan bize dönen yanıt haricinde bir de zaman damgası (timestamp) var.

indexeddb içeriği

Tekrar uygulamadaki butona bastığımızda GitHub’dan alınan kullanıcı bilgilerinin yine ekrana yazıldığını ama GitHub sunucularına istemcimizden bir HTTP isteği çıkmadığını görüyoruz.

sonraki http istekleri

IndexedDB kaydı içerisindeki zaman damgası, GitHub sunucularından HTTP yanıtını aldığımız anın üstüne localforage store’unda tanımladığımız önbellekleme süresinin eklenmiş hâline karşılık geliyor. O zaman dolana kadar aynı API ucuna yapılacak tüm HTTP isteklerinin yanıtları IndexedDB’deki kayıttan verilecek ve GitHub sunucularına yeni bir istek yapılmayacak.

Sonuç

Sonuç olarak bir önceki önbellekleme yazısının finalini tekrar etmiş olayım. İlk bakışta çocuksu bir heyecanla her API ucunu önbelleklemek geliştirici olarak içimizden geçse de, hangi API ucunun neden ve ne kadar süreyle önbelleklenmesi gerektiğini ve önbelleklenmediğindeki maliyetini analiz etmeden bu işlere girişmek veri tutarsızlığı ve test zorlukları gibi birçok konu özelinde daha çok baş ağrıtabilir. Son olarak yazıda bahsi geçen basit uygulamayı da paylaşarak bitireyim.

Kaynaklar

--

--