处理快速路线内多个功能/方案的最佳方法?

时间:2018-10-22 23:54:38

标签: node.js express

我的Express应用程序中有许多端点,它们具有许多条件。我想找到最适合他们的设计模式,而无需重复太多自己。

这是我最简单的路线之一:

 router.post('/reset/:token',
    asyncMiddleware(async(req, res, next) => { await reset(req, res, next, pino); })
  );

reset()内部,我需要检查几件事,例如:

  • 如果所有必需的身体参数都在这里
  • 如果来自解密令牌的电子邮件与来自数据库的电子邮件相匹配
  • 如果密码保存成功。

我想检查那些没有强大功能的情况,但是我不知道什么是最好的方法

整个路线代码

export async function reset(req, res, next) {
  const email = req.body.email;
  if (!email) return res.status(400).json(Error.paramsMissing('email'));

  const user = await userAssociatedWithEmail(req.body.email);
  if (!user) {
    return res.status(501).json(Error.noActiveUserAssociatedWithEmail);
  }

  // Generate token
  const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');
  const emailSent = await sendForgotEmail(token, user);

  if (!emailSent) return res.status(500).json(Error.emailNotSent);
  else return res.json({ status: 'success', message: 'Email sent successfully.' });
}

我想做什么

我想要的最终结果

export async function reset(req, res, next) {
  const email = req.body.email;
  if (!email) return res.status(400).json(Error.paramsMissing('email'));

  // If error inside userAssociatedWithEmail, I'd like to stop execution and 
  // return res.status(501).json(Error.noActiveUserAssociatedWithEmail) from inside 
  // that function, without having to add an if condition below as exists in the 
  // original code above
  const user = await userAssociatedWithEmail(req.body.email); 

  const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');

  // Again I'd like to return res.status(500).json(Error.emailNotSent) 
  // from inside sendForgotEmail IF there is an error
  const emailSent = await sendForgotEmail(token, user); 

  // If everything is successful, finally I'd return this
  return res.json({ status: 'success', message: 'Email sent successfully.' });
}

用字解释结果:

如果可能的话,我希望能够处理条件和情况而不必在主reset函数中进行处理(又名,而不必将响应存储在变量中,检查变量并如果发生错误,请在主功能中输入return

例如,代替:

  const allParamsAreValid = validParams(token, email, new_password, res);
  if (!allParamsAreValid) return;

我想做类似的事情:

  validateParams(token, email, new_password, res);

然后在validateParams()内,如果缺少参数,除了用res.json({})设置响应之外,我将强制退出程序。

有可能吗?

2 个答案:

答案 0 :(得分:1)

您可以使所有返回承诺的异步函数以您要发送的状态和值拒绝承诺。然后,您可以在一个地方处理被拒绝的承诺:

export async function reset(req, res, next) {
    try {
        const email = req.body.email;
        if (!email) return res.status(400).json(Error.paramsMissing('email'));

        // If error inside userAssociatedWithEmail, I'd like to stop execution and 
        // return res.status(501).json(Error.noActiveUserAssociatedWithEmail) from inside 
        // that function, without having to add an if condition below as exists in the 
        // original code above
        const user = await userAssociatedWithEmail(req.body.email); 

        const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');

        // Again I'd like to return res.status(500).json(Error.emailNotSent) 
        // from inside sendForgotEmail IF there is an error
        const emailSent = await sendForgotEmail(token, user); 
        // If everything is successful, finally I'd return this
        res.json({ status: 'success', message: 'Email sent successfully.' });

    } catch(e) {
        res.status(e.status || 500).json(e.errData)
    }
}

然后,如果所有异步函数都具有错误条件,它们将被拒绝,并根据被拒绝的原因设置e.statuse.errData。这将使您拥有一个常见的错误处理程序,并让async函数为您将所有被拒绝的承诺收集到您的try / catch中。这是您在希望整个函数完成的一系列await调用中处理拒绝的一种干净方法。

然后,您还需要确保asyncMiddleware()函数也没有发送响应(无法真正告知其目的是什么)。您没有显示该代码,所以我看不到它在做什么。

您没有显示任何使用validateParams()的代码,但是如果它是同步的,则它可能会抛出一个异常,并在其上设置了正确的字段,而try/catch也会捕获它就像它会捕获异步拒绝一样。

例如:

function validateParams(token, email, new_password) {
    let err = new Error();
    err.errData = {status: 'error'};
    if (!token) {
       err.errData.message = 'invalid token';
       throw err;
    }
    if (!email) {
       err.errData = Error.paramsMissing('email');
       throw err;
    }
    if (!new_password) {
       err.errData.message = 'invalid new password');
       throw err;
    }
}

如果您愿意,也可以在validateParams()中发送错误响应,但我认为这样做不干净,因为它们可以一次尝试收集所有错误,包括所有await异步调用抓住了路由处理程序,坦率地说,要在某些函数调用中而不在其他函数调用中发送响应,这是更具可读性和可理解性的代码。我尝试将所有错误和成功回复都保持在同一级别。然后,很容易跟踪并避免意外发送多个响应。

然后,在您的路由处理程序中,您只需像这样调用validateParams(...)。如果抛出该异常,则您的try / catch将捕获该异常并发送相应的错误。如果没有错误,则执行将继续。

答案 1 :(得分:0)

由于您将 res 对象传递给 validateParams 方法,因此您可以执行以下操作,

async function validateParams(token, email, new_password, res) {
  if (token && emal && new_password &&  res) {
    // all values are available
    // perform your desired operation 
  } else {
    // exit from the method and pass info to the client
    return res.json({ message: 'Invalid parameter' });
  }
}

在这种情况下,您要做的就是调用validateParams。

await validateParams(token, email, new_password, res);

如果缺少参数,服务器将立即将控件传递给客户端。否则,您可以在那里进行操作。