Skip to content

Instantly share code, notes, and snippets.

@rkatic
Last active March 9, 2023 17:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkatic/980492390702647f031e4b77827de8f6 to your computer and use it in GitHub Desktop.
Save rkatic/980492390702647f031e4b77827de8f6 to your computer and use it in GitHub Desktop.
Simple single resource cache.
const isNotExpired = x => x && x.exp >= Date.now()
export function resourceCache (get, isValid = isNotExpired, initialData = undefined) {
let data = initialData
let pending = null
return async () => {
if (pending) return pending
if (!isValid(data)) {
try {
pending = get()
data = await pending
} finally {
pending = null
}
}
return data
}
}

Example:

import { resourceCache } from './resourceCache'

// Given a resource resolver, create one that auto caches
const getAuth = resourceCache(async () => {
  // Fetch the resource
  const token = await fetchApiToken()
  
  // Expire it after 5 minutes
  const exp = Date.now() + (5 * 60 * 1000)
  
  return { token, exp }
})

export async function fetchMyApi(path, options, retryOn401 = true) {
  const auth = await getAuth()
  
  const response = await fetch(baseURL + path, {
    ...options,
    headers: {
      Authorization: `Bearer ${auth.token}`,
      ...options?.headers,
    }
  })
  
  if (retryOn401 && response.status === 401) {
    // Invalidate used `auth` and retry.
    auth.exp = 0
    return fetchMyApi(path, options, false)
  }

  if (!response.ok) { ... }
  
  return response.json()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment