Search code examples
node.jsmongodb-atlasgoogle-cloud-storage

Writing To GCS From Mongo Atlas Functions Not Working


I am trying to write a blob to a bucket using the save() function (sample here) from the GCS Node.js SDK from Google inside a Atlas Cloud Function that get's triggered on a DB event.

exports = async function(changeEvent) {
  const { Storage } = require('@google-cloud/storage');
  const storage = new Storage({
    projectId: '<project-id>',
    credentials: JSON.parse(context.values.get('GOOGLE_APPLICATION_CREDENTIALS'))
  });
  const destFilename = '<filename>';
  const bucketName = '<bucket-name>';
  const contents = 'these are my contents';
  return await storage.bucket(bucketName).file(destFilename).save(contents);
}

I can confirm the following:

  1. The client is correctly authenticated
  2. Permissions are correct

My problem is that I do not know what the problem because when I run the function it throws me this error:

{"_readableState":{"objectMode":false,"highWaterMark":{"$numberLong":"16384"},"buffer":{"head":null,"tail":null,"length":{"$numberLong":"0"}},"length":{"$numberLong":"0"},"pipes":null,"pipesCount":{"$numberLong":"0"},"flowing":false,"ended":true,"endEmitted":true,"reading":false,"sync":false,"needReadable":false,"emittedReadable":false,"readableListening":false,"resumeScheduled":false,"paused":false,"emitClose":true,"autoDestroy":false,"destroyed":false,"defaultEncoding":"utf8","awaitDrain":{"$numberLong":"0"},"readingMore":false,"decoder":null,"encoding":null},"readable":false,"_events":{"prefinish":{},"close":[{},{}],"end":{},"finish":{},"error":{}},"_eventsCount":{"$numberInt":"5"},"_maxListeners":{"$undefined":true},"_writableState":{"objectMode":false,"highWaterMark":{"$numberLong":"16384"},"finalCalled":false,"needDrain":false,"ending":true,"ended":true,"finished":true,"destroyed":false,"decodeStrings":true,"defaultEncoding":"utf8","length":{"$numberDouble":"0"},"writing":false,"corked":{"$numberLong":"0"},"sync":false,"bufferProcessing":false,"onwrite":{},"writecb":null,"writelen":{"$numberLong":"0"},"bufferedRequest":null,"lastBufferedRequest":null,"pendingcb":{"$numberInt":"0"},"prefinished":true,"errorEmitted":false,"emitClose":true,"autoDestroy":false,"bufferedRequestCount":{"$numberLong":"0"},"corkedRequestsFree":{"next":null,"entry":null,"finish":{}}},"writable":false,"allowHalfOpen":true,"_transformState":{"afterTransform":{},"needTransform":false,"transforming":false,"writecb":null,"writechunk":null,"writeencoding":"buffer"},"updateHashesOnly":true,"crc32cEnabled":true,"md5Enabled":false,"crc32cExpected":{"$undefined":true},"md5Expected":{"$undefined":true}}

Screenshot-of-error


Solution

  • So after much back an forth I have decided against using the Node.js Google Cloud Storage SDK. Instead I am using the Storage API directly in conjunction with the Node.js Google Auth SDK to make authenticated requests. Here is a sample snippet:

    const {GoogleAuth} = require('google-auth-library');
    
    const auth = new GoogleAuth({
            credentials: JSON.parse(context.values.get('GOOGLE_APPLICATION_CREDENTIALS')),
            scopes: 'https://www.googleapis.com/auth/cloud-platform'
        });
    
    const { status, data } = await auth.request({
        url: uploadUrl,
        method: 'POST',
        headers: {
          'Content-Type': 'image/jpeg'
        },
        data: imageData // Ensure this is the binary data of the image
      });
    

    Note.. I also tried out different approaches as I assumed it being an asynchronies problem and managed to get a more explicit error messages saying the following: TypeError: 'finally' is not a function

    ChatGPT told me the following about the above:

    The error you're encountering, "TypeError: 'finally' is not a function," suggests that there might be a compatibility issue with the JavaScript environment in which your MongoDB Atlas function is running. The finally method is part of the Promise API in modern JavaScript, but it seems like it might not be supported in your current environment.