Automatically revalidate KV Store cache on change with Database Webhooks in Supabase

Jon Meyers
InstructorJon Meyers
Share this video with your friends

Social Share Links

Send Tweet
Published 2 years ago
Updated 2 years ago

Supabase Function Hooks allow us to subscribe to change events in the database - such as insert, update and delete - and make a HTTP request with the changed data.

In this lesson, we refactor our revalidate route to handle inserts, updates and deletes.

Additionally, we create a Function Hook to subscribe to all change events on the articles table, and automatically send a POST request to the revalidate route of our Cloudflare Worker.

This automatically refreshes the KV store anytime a value is changed in the database, and decouples the revalidation of our cache, from our user requesting data. This means, theoretically, users should never have to wait for a request to the Supabase origin server, as the cache is automatically populated, updated and cleared to remain in sync with the database.

Code Snippets

Update Revalidate route to handle insert, update and delete

router.post(
  "/revalidate",
  withContent,
  async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }) => {
    const { type, record, old_record } = request.content;
    const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

    if (type === "INSERT" || type === "UPDATE") {
      await writeTo(ARTICLES, `/articles/${record.id}`, record);
    }

    if (type === "DELETE") {
      await ARTICLES.delete(`/articles/${old_record.id}`);
    }

    const { data: articles } = await supabase.from("articles").select("*");
    await writeTo(ARTICLES, "/articles", articles);

    return json({ received: true });
  }
);

Run wrangler development server

npx wrangler dev

Publish Cloudflare Worker with Wrangler CLI

npx wrangler publish

Resources

Jon Meyers: [0:00] Currently, our page is showing cached data if it's available, but if the data in the database changes, like our Cool Second blog becomes our Very Cool Second blog, then the only way to update our cache and display that new title is to send a POST request to our revalidate route, passing through the id for the article that we would like to update with fresh data from Supabase. [0:22] If we send this request and refresh the browser, we'll see our title has updated, but wouldn't it be great if we could subscribe to any changes that happen in our Supabase database and automatically call this revalidate endpoint, telling it what had changed?

[0:36] We could do exactly that with Supabase function hooks. From our Supabase dashboard, we want to go to Database, and then Function Hooks, and click Enable Hooks. We then want to create a new function hook. The name of this one is going to be revalidate_cache

[0:51] We then tell it which table we would like to subscribe to changes on -- in our case, articles -- and which events we care about. We want to know about inserts, updates, and deletes as we will need to modify our cache for all of these.

[1:03] The type of hook is going to be HTTP Request. The type of method that we want to send for our request is going to be POST. We then need the URL for our hosted revalidate endpoint. We can get that by publishing a new version of our Cloudflare worker by saying npx wrangler publish.

[1:21] This will print out our hosted URL here and we just need to prepend this with https:// and then paste in our URL. Lastly, we append our revalidate path and click Confirm.

[1:37] Now, back over in our revalidate route, rather than getting an id passed across when our function hook calls our revalidate route, we're going to get the type, so whether this is an insert update or delete action, and then the new record, if this is an insert or update, or the old_record, if this is a delete action.

[1:56] Since we have this full record, we don't need to go and select anything from Supabase. We can check if the type is INSERT or the type is UPDATE. Then we want to update the cache by calling writeTo, passing it the ARTICLES cache and then the path for our article, which will be /articles/${record.id}, which is the record coming in from our request. We also want to pass in that record as the data that we want to write to the cache.

[2:25] If the type is DELETE then we want to await a call to our cache, asking it to delete the value at the path /articles/${old_record.id}. This is the old record that has been deleted from our Supabase database.

[2:42] We can save this file and deploy a new version of our Cloudflare Worker by typing npx wrangler publish, and this will print out our production URL, which we can copy from here and paste in our browser along with our /articles endpoint. We can now see each of our three articles.

[2:58] However, if we decide it's time to publish our Very Cool Second blog, we can come across to Supabase, find out Very Cool Second blog and toggle out is_published column from false to true. If we navigate back to our Cloudflare Worker and refresh, we should see our Very Cool Second blog is now published.

[3:15] If we navigate to that particular article, we'll see that its data has also been automatically revalidated using Supabase function hooks.

egghead
egghead
~ 24 minutes ago

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today