简体   繁体   中英

Exporting data in a node file after it is returned from an API call to AWS Secrets Manager

Background

I am storing the database information for a RDS in AWS in the secrets manager. I am using the AWS-SDK to retrieve the password and other data so I can create a secrets object at run time. When I try and create this object and then export it, the object that is exported is always lacking the data that I expect to be returned from the aws-sdk.

What I Have Tried -

I have tried using async await but it is still exporting the object before all of the data is correctly populated.

Example

const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
  username: '',
  password: '',
  host: '',
  port: '',
  database: '',
  email: 'example@example.com',
  emailPassword: 'SomePassword'
};

const client = new AWS.SecretsManager({
  region: region
});

client.getSecretValue({ SecretId: secretName }, async (err, data) => {
  if (err) {
    throw err;
  } else {
    const res = await JSON.parse(data.SecretString);
    secrets.username = res.username;
    secrets.password = res.password;
    secrets.host = res.host;
    secrets.port = res.port;
    secrets.database = res.database;
  }
});

module.exports = secrets;

Question

The obvious problem here is not creating the promise correctly but I am not sure why my attempts are completing the promises after the file gets exported. If I console.log(secrets) in another file in some cases it will output the object missing data then show the data returned by the promise a few seconds later after when I console.log(secrets) inside of the function.

What is the proper way to build this object secrets and export it once the data is returned from AWS and added to the object secrets ?

According to the docs , the second argument to getSecretValue is a callback function, so there's no need to use async/await since async/await is meant to work with promises.

Removing async/await should work.

client.getSecretValue({ SecretId: secretName }, (err, data) => {
  if (err) {
    throw err;
  } else {
    const res = JSON.parse(data.SecretString);
    secrets.username = res.username;
    secrets.password = res.password;
    secrets.host = res.host;
    secrets.port = res.port;
    secrets.database = res.database;
  }
}); 

However, you're exporting the secrets object synchronously, and its properties are getting set asynchronously.

Instead, you can return a promise for your other modules to consume.

const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
  email: 'example@example.com',
  emailPassword: 'SomePassword'
};

const client = new AWS.SecretsManager({
  region: region
});

const promise = new Promise((resolve, reject) => {
  client.getSecretValue({ SecretId: secretName }, async (err, data) => {
    if (err) {
      reject(err);
    } else {
      const res = await JSON.parse(data.SecretString);
      secrets.username = res.username;
      secrets.password = res.password;
      secrets.host = res.host;
      secrets.port = res.port;
      secrets.database = res.database;
      resolve(secrets);
    }
  });
})

module.exports = promise;

Then, in some other module that consumes this one, you can use async/await since we now have a promise.

import {promise} from "./this-module";

(async () => {
  const secrets = await promise;
  console.log(secrets);
})();

Update

I'm not sure if this will work, but it's worth a shot. Here, set module.exports only after secrets is set. If this doesn't work, then I would ask a new question on StackOverflow about how to export resolved promises with CommonJS (which is the module format that you're using).

const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
  email: 'example@example.com',
  emailPassword: 'SomePassword'
};

const client = new AWS.SecretsManager({
  region: region
});

const promise = new Promise((resolve, reject) => {
  client.getSecretValue({ SecretId: secretName }, async (err, data) => {
    if (err) {
      reject(err);
    } else {
      const res = await JSON.parse(data.SecretString);
      secrets.username = res.username;
      secrets.password = res.password;
      secrets.host = res.host;
      secrets.port = res.port;
      secrets.database = res.database;
      resolve(secrets);
    }
  });
});

(async () => {
  module.exports = await promise;
})();
client.getSecretValue({ SecretId: secretName     }).subscribe(data=>{
    const res =JSON.parse(data.SecretString);
    secrets.username = res.username;
    secrets.password = res.password;
    secrets.host = res.host;
    secrets.port = res.port;
    secrets.database = res.database;
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM