Custom Svelte Store with Appwrite and Caching

Custom Svelte Store with Appwrite and Caching

·

4 min read

Who wouldn’t love cache, right? Let’s see how we can cache data with Svelte & Appwrite!

We're going to explore how we can create a Svelte store that caches our data and is dynamically updated.

Luckily for us, it’s pretty easy.

The TL;DR is:

  • Create a store with set, subscribe, and load
  • Set the data to the cache
  • Update the cache by subscribing to the data changes
  • Update the data dynamically by calling the load function in your component

Let's set everything up 📦

We’ll start by creating an appwrite.js store to make our life easier:

import { Client } from 'appwrite';

const server = {
    endpoint: import.meta.env.VITE_APP_ENDPOINT.toString(),
    project: import.meta.env.VITE_APP_PROJECT.toString(),
    collection: import.meta.env.VITE_APP_COLLECTION_ID.toString(),
    database: import.meta.env.VITE_APP_DATABASE_ID.toString()

};

const client = new Client();

client.setEndpoint(server.endpoint).setProject(server.project);

export { client, server };

You can check a complete example here

This allows us to access Appwrite's sdk from wherever we want. Remember to add all the endpoints in the .env file at your project's root.

The fun begins! 🥳

Now let's initialize another store where we will implement our caching:

import { client, server } from './appwrite'; // This is the store we created previously
import { Databases } from 'appwrite';
import { writable } from 'svelte/store';
import { browser } from '$app/env'; // We'll use this to check if we are in the browser

function createDocumentsListStore() {
// Magic unicorns 🦄 
}

export const documentsList = createDocumentsListStore();

Great! Let's work a little bit on that function. We want to create a writable store that can fetch our cached data, and is easy to update.

function createDocumentsListStore() {
    const { subscribe, set } = writable({
/* Check if we're in the browser. 
If we are check the session storage for a item named documents, and parse it. This is our response. 
If we're not in the browser or if there is no item stored the response is null */
        response: browser ? JSON.parse(sessionStorage.getItem('documents')) : null
    });

    return {
        subscribe,
        set,
        load: async ( queries ,limit, offset) => {
            try {
                const database = new Databases(client, server.database);
                const response = database.listDocuments(
                server.collection, // We imported server from the appwrite.js store
                queries,
                limit,
                offset,
                undefined,
                undefined,
                ['created_at'],
                ['DESC']
            );
                set({
                    response
                });
            } catch (error) {
               // Handle the error
            }
        }
    };
}

So, with this function, we check if there is data in the session storage and set the response to it.

Where's my cache? 🤔

We have a small problem: we've yet to save anything in our cache!

Luckily for us it's pretty straightforward:

if (browser) {
    documentsList.subscribe((n) => sessionStorage?.setItem('documents', JSON.stringify(n.response ?? '')));
}

We simply subscribe to the store and save the data in the session storage each time it changes.

✅ set, ✅ subscribe, 🔧 load

Now we have another problem! The data is set, and our cache is always up-to-date... but the data never changes! That's what "load" is for ;)

For example, in our component we can do something like this:

<script>
import { documentsList } from './store';
let queries, limit, offset

$: documentsList.load(queries, limit, offset);
</script>

{#if $documentsList?.response?.total}
    {#each $documenstList.response.document as document}
        <pre>{document}</pre>
    {/each}
{/if}

This way, each time one of the arguments passed to "load" changes, the data will be updated!

And now we have an Appwrite store with cached data!

Let's put it all together 🙌

In the end our store looks like this:

import { client, server } from './appwrite'; 
import { Databases } from 'appwrite';
import { writable } from 'svelte/store';
import { browser } from '$app/env'; 


function createDocumentsListStore() {
    const { subscribe, set } = writable({
        response: browser ? JSON.parse(sessionStorage.getItem('documents')) : null
    });

    return {
        subscribe,
        set,
        load: async ( queries ,limit, offset) => {
            try {
                const database = new Databases(client, server.database);
                const response = database.listDocuments(
                server.collection, 
                queries,
                limit,
                offset,
                undefined,
                undefined,
                ['created_at'],
                ['DESC']
            );
                set({
                    response
                });
            } catch (error) {
               // Handle the error
            }
        }
    };
}

export const documentsList = createDocumentsListStore();
if (browser) {
    documentsList.subscribe((n) => sessionStorage?.setItem('documents', JSON.stringify(n.response ?? '')));
}

🏁 Conclusion

And that’s all it takes to implement a custom svelte store with Appwrite & caching. You can view the following resources as well if you want to explore Appwrite further:

Appwrite Docs Appwrite Discord Appwrite GitHub