Search code examples
google-apps-scriptcaching

Google App Scripts User Cache Service: Accessing Cache Information in a Different Script but Same User


Looking into a way of sharing data via Google App Scripts's Cache Services from one web app to another.

Users load up the first webpage and filled out their information. Once submitted a function is run on this data and stored via the cache.

CacheService.getUserCache().put('FirstName','David')
CacheService.getUserCache().put('Surname','Armstrong')

Console log shows reports back that these two elements have been saved to cache.

However in the second web app when cache is called upon the console log returns null

var cache = CacheService.getUserCache().get('Firstname');
var cache2 = CacheService.getUserCache().get('Surname'); 

console.log(cache)
console.log(cache2)

Any ideas?


Solution

  • A possible solution would be to implement a service to synchronize the cache between web apps.

    This can be achieved by creating a WebApp that via POST allows to add to the ScriptCache of the "Cache Synchronizer" the UserCache of the individual Web Apps.

    The operation would be very simple:

    • From the web app that we want to synchronize, we check if we have cache of the user.

      • If it exists, we send it to the server so that it stores it.
      • If it does not exist, we check if the server has stored the user's cache.

    Here is a sketch of how it could work.

    CacheSync.gs
    const cacheService = CacheService.getScriptCache()
    const CACHE_SAVED_RES = ContentService
      .createTextOutput(JSON.stringify({ "msg": "Cache saved" }))
      .setMimeType(ContentService.MimeType.JSON)
    
    const doPost = (e) => {
      const { user, cache } = JSON.parse(e.postData.contents)
      const localCache = cacheService.get(user)
      if (!localCache) {
        /* If no local data, we save it */
        cacheService.put(user, JSON.stringify(cache))
        return CACHE_SAVED_RES
      } else {
        /* If data we send it */
        return ContentService
          .createTextOutput(JSON.stringify(localCache))
          .setMimeType(ContentService.MimeType.JSON)
      }
    }
    
    ExampleWebApp.gs
    const SYNC_SERVICE = "<SYNC_SERVICE_URL>"
    const CACHE_TO_SYNC = ["firstName", "lastName"]
    const cacheService = CacheService.getUserCache()
    
    const syncCache = () => {
      const cache = cacheService.getAll(CACHE_TO_SYNC)
      const options = {
        method: "POST",
        payload: JSON.stringify({
          user: Session.getUser().getEmail(),
          cache
        })
      }
      if (Object.keys(cache).length === 0) {
        /* If no cache try to fetch it from the cache service */
        const res = UrlFetchApp.fetch(SYNC_SERVICE, options)
        const parsedResponse = JSON.parse(JSON.parse(res.toString()))
        Object.keys(parsedResponse).forEach((k)=>{
          console.log(k, parsedResponse[k])
          cacheService.put(k, parsedResponse[k])
        })
      } else {
        /* If cache send it to the sync service */
        const res = UrlFetchApp.fetch(SYNC_SERVICE, options)
        console.log(res.toString())
      }
    }
    
    const createCache = () => {
      cacheService.put('firstName', "Super")
      cacheService.put('lastName', "Seagull")  
    }
    
    const clearCache = () => {
      cacheService.removeAll(CACHE_TO_SYNC)
    }
    

    Additional information

    • The synchronization service must be deployed with ANYONE access. You can control the access via an API_KEY.
    • This is just an example, and is not fully functional, you should adapt it to your needs.
    • The syncCache function of the web App is reusable, and would be the function you should use in all Web Apps.
    • There is a disadvantage when retrieving the cache, since you must provide the necessary keys, which forces you to write them manually (ex CACHE_TO_SYNC).
    • It could be considered to replace ScriptCache with ScriptProperties.
    Documentation