Javascript 普通函数的注解/装饰器

Javascript annotations / decorators on normal functions

我正在开发一个 Next.js 应用程序,我有一个按以下方式定义的 API:

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'GET') {
    fn1Get(req, res);
  } else if (req.method === 'POST') {
    fn1Post(req, res);
  } else {
    res.status(501).json({ operation: `${req.method}: not implemented` });
  }
}
async function fn1Get(
  req: NextApiRequest,
  res: NextApiResponse
): Promise<void> {
  const authenticated = await checkAuth(req, res);
  if (authenticated) {
      // Get Stuff
      res.status(200).json({status: 'all right!'});
  }
}
async function fn1Post(
  req: NextApiRequest,
  res: NextApiResponse
): Promise<void> {
  const authenticated = await checkAuth(req, res);
  if (authenticated) {
      // Post Stuff
      res.status(201).json({status: 'all right!'});
  }
}
const checkAuth = async (req: NextApiRequest, res: NextApiResponse) => {
  const tokenValid = await extnernalApiCall(getToken(req));
  if (!tokenValid) {
    res.status(403).json({ error: 'Authentication Failed' });
  }
  return tokenValid
};

我正在尝试找到一个更简单的设置来定义经过身份验证的方法,而不是在其中添加行 const authenticated = await checkAuth(req, res);

在 Java 或 Python 等其他语言中,我可以使用装饰器/注释/AOP,例如:

@checkAuth
async function fn1Get(
  req: NextApiRequest,
  res: NextApiResponse
):

我可以在 javascript 中做一些接近它的事情吗?也许通过包装函数,and/or 使用 bind/call/apply??

伪代码示例:

const checkAuth = async (fn) => {
  const req = arguments[1];
  const res = arguments[2];
  const tokenValid = await extnernalApiCall(getToken(req));
  if (!tokenValid) {
    res.status(403).json({ error: 'Authentication Failed' });
  }
  return fn(arguments);
}
async function fn1Get = checkAuth(_fn1Get(
  req: NextApiRequest,
  res: NextApiResponse
): Promise<void> {
  const authenticated = await checkAuth(req, res);
  if (authenticated) {
      // Get Stuff
      res.status(200).json({status: 'all right!'});
  }
})

如您所见,我要验证的所有函数都会收到相同的两个参数 reqres(请求和响应),而我的验证函数也需要这两个参数来从 req 获取要进行身份验证的令牌,如果未通过身份验证,则在 res 中写入 403

我使用的技术是 Next.js React 17、TypeScript、ECMA6

是的,您可以使用包装函数来实现这一点(这基本上就是装饰器的作用)。该包装函数必须 return 一个函数。类似于以下内容(您必须相应地调整类型):

const checkAuth = (fn) => {
  return async (req: NextApiRequest,res: NextApiResponse): Promise<void> => {
    const tokenValid = await extnernalApiCall(getToken(req));
    if (!tokenValid) {
      res.status(403).json({ error: 'Authentication Failed' });
    } else {
      fn(req, res);
    }
  }
}

const fn1Get = checkAuth((
  req: NextApiRequest,
  res: NextApiResponse
): Promise<void> => {
  // Get Stuff
  res.status(200).json({status: 'all right!'});
})

话虽如此,我对next.js并不熟悉。可能有一种方法可以注册在每个请求上触发的中间件处理程序,而无需显式包装每个处理程序。