Home > database >  In NodeJS, can I create a promise and catch its failure later?
In NodeJS, can I create a promise and catch its failure later?

Time:05-26

I'm writing some code that grabs some result asynchronously and stores it until later, when another function needs it, sort of like eager loading it. (In my specific case I'm grabbing a secret from AWS Secrets manager, but whatever.) My code looks like this:

const secretPromise = new Promise((resolve, reject) => {
  try {
    const credentialsJSON = await new AWSController().getSecret("my-credentials");
    resolve(JSON.parse(credentialsJSON));
  } catch (e) {
    reject(new Error(`Error getting credentials: ${e.message}`));
  }
});

// in an expressJS route handler:
router.get("/groups", async (request, response) => {
  try {
    const credentials = await secretPromise;
    const result = await doSomething(credentials);
    response.send(JSON.stringify(result));
  } catch (error){
    response.status(503).send(`Error: ${error.message)`);
  }
});

What I didn't realize was that if there's no handler for this promise, it will throw an error and crash my nodeJS code immediately. Is there a way to store the result or error and handle it later? I don't want my server to crash just because one API function won't work.

CodePudding user response:

You create the secretPromise early, outside of the route handler. It may therefore be rejected before the route handler is called, when there is no try-catch block that would catch that rejection.

A rejected secretPromise causes every subsequent GET /groups request to fail, you could handle this without a rejection:

const secretPromise = new Promise((resolve, reject) => {
  try {
    const credentialsJSON = await new AWSController().getSecret("my-credentials");
    resolve(JSON.parse(credentialsJSON));
  } catch (e) {
    resolve({error: new Error(`Error getting credentials: ${e.message}`)});
  }
});

// in an expressJS route handler:
router.get("/groups", async (request, response) => {
  try {
    const credentials = await secretPromise;
    if (secretPromise.error) throw secretPromise.error;
    const result = await doSomething(credentials);
    response.send(JSON.stringify(result));
  } catch (error){
    response.status(503).send(`Error: ${error.message)`);
  }
});

CodePudding user response:

The await inside secretPromise is not within an async function therefore the code isn't valid. Also there's no need to wrap it in a Promise.

To eagerly fetch the credentials before the API is called, I would simply write it like this:

let credentials;
try {
  const credentialsJSON = await new AWSController().getSecret("my-credentials");
  credentials = JSON.parse(credentialsJSON);
} catch (e) {
  credentials = new Error(`Error getting credentials: ${e.message}`);
 }
};


// in an expressJS route handler:
router.get("/groups", async (request, response) => {
  try {
    if (credentials instanceof Error) {
      throw credentials;
    }

    const result = await doSomething(credentials);
    response.send(JSON.stringify(result));
  } catch (error){
    response.status(503).send(`Error: ${error.message)`);
  }
});
  • Related