Search code examples
node.jsmongodbgoogle-cloud-pubsubmongodb-atlas

How To Make An Authenticated Request From Mongo Atlas Triggers To GCP PubSub


I have the following code:

exports = function(changeEvent) {
  var {PubSub} = require("@google-cloud/pubsub");
  var avro = require("avro-js");
  const keyFilename = context.values.get("GOOGLE_APPLICATION_CREDENTIALS")
  const projectId = "<project_name>"
  const pubSubClient = new PubSub({projectId, keyFilename});
  const topicName = "<topic_name>"
  const topic = pubSubClient.topic(topicName);
  try {
    const data = "something";
    const dataBuffer = Buffer.from(data);
    return topic.publish(dataBuffer)
      .then((messageId) => console.log(`Message ${messageId} published.`))
      .catch((err) => console.log(`Error publishing message: ${err}`));
  } catch(err) {
    console.log("Error: ", err.message);
  }
};

When running the above it returns back the following:

Error publishing message: FunctionError: TypeError: 'createReadStream' is not a function
> result: 
{
   "$undefined": true
}
> result (JavaScript): 
EJSON.parse('{"$undefined":true}')

Something to point out:

  1. I am not the first to encounter this problem but both of the threads did not receive much attention
  2. The GOOGLE_APPLICATION_CREDENTIALS value ought to be a path to the secret called service-account.. it's a json of a service account key from GCP. What confuses me though is that if I console.log the path it prints out the secret as json and not the path to the secret enter image description here

At this point I am not sure what it can be. At first I thought it could be a async vs sync problem. But I tried both approaches resulting in the same error. Another problem could be the authentication with the client. But the error message does not provide me with much and when searching for createReadStream I can't find anything useful.


Solution

  • This could be an authentication issue.

    The GOOGLE_APPLICATION_CREDENTIALS environment variable typically expects a file path to the JSON key file, not the JSON content itself. However, in serverless environments like MongoDB Atlas Triggers, you might not have access to the filesystem in a traditional way.

    You can directly pass the credentials as an object instead:

    const credentials = JSON.parse(context.values.get("GOOGLE_APPLICATION_CREDENTIALS_JSON"));
    const pubSubClient = new PubSub({ projectId, credentials }); 
    

    Please see more arguments of type ClientConfig that you can pass to the PubSub client here https://googleapis.dev/nodejs/pubsub/latest/global.html#ClientConfig.

    This may also be helpful: https://github.com/googleapis/nodejs-pubsub/issues/367