Functional programming 您将如何使用Ramda.js重构此函数?

Functional programming 您将如何使用Ramda.js重构此函数?,functional-programming,ramda.js,Functional Programming,Ramda.js,我正在努力学习Ramda.js,但要想在Ramda中事情看起来有多简单一直是个挑战。如果您是Ramda或函数式编程专家,您将如何重构它 const validateFirebaseIdToken = async (req, res, next) => { console.log("Check if request is authorized with Firebase ID token"); if ( (!req.headers.authorization ||

我正在努力学习Ramda.js,但要想在Ramda中事情看起来有多简单一直是个挑战。如果您是Ramda或函数式编程专家,您将如何重构它

const validateFirebaseIdToken = async (req, res, next) => {
  console.log("Check if request is authorized with Firebase ID token");

  if (
    (!req.headers.authorization ||
      !req.headers.authorization.startsWith("Bearer ")) &&
    !(req.cookies && req.cookies.__session)
  ) {
    console.error(
      "No Firebase ID token was passed as a Bearer token in the Authorization header.",
      "Make sure you authorize your request by providing the following HTTP header:",
      "Authorization: Bearer <Firebase ID Token>",
      'or by passing a "__session" cookie.'
    );
    res.status(403).send("Unauthorized");
    return;
  }

  let idToken;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith("Bearer ")
  ) {
    console.log('Found "Authorization" header');
    // Read the ID Token from the Authorization header.
    idToken = req.headers.authorization.split("Bearer ")[1];
  } else if (req.cookies) {
    console.log('Found "__session" cookie');
    // Read the ID Token from cookie.
    idToken = req.cookies.__session;
  } else {
    // No cookie
    res.status(403).send("Unauthorized");
    return;
  }

  try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    //console.log("ID Token correctly decoded", decodedIdToken);
    req.user = decodedIdToken;
    next();
    return;
  } catch (error) {
    console.error("Error while verifying Firebase ID token:", error);
    res.status(403).send("Unauthorized");
    return;
  }
};
const validateFireBaisedToken=async(请求、恢复、下一步)=>{
日志(“检查请求是否使用Firebase ID令牌授权”);
如果(
(!req.headers.authorization)||
!req.headers.authorization.startsWith(“承载人”))&&
!(请求cookies和请求cookies.\u会话)
) {
控制台错误(
“未在授权标头中将Firebase ID令牌作为承载令牌传递。”,
“请确保通过提供以下HTTP标头来授权您的请求:”,
“授权:持票人”,
'或通过传递“\u会话”cookie。”
);
资源状态(403)。发送(“未授权”);
返回;
}
让idToken;
如果(
请求授权&&
请求头、授权、启动和(“持票人”)
) {
log('Found“Authorization”header');
//从授权标头读取ID令牌。
idToken=req.headers.authorization.split(“承载人”)[1];
}else if(请求cookies){
log('Found“\uuuu session”cookie');
//从cookie中读取ID令牌。
idToken=请求cookies.\uuuu会话;
}否则{
//没有饼干
资源状态(403)。发送(“未授权”);
返回;
}
试一试{
const decodedIdToken=wait admin.auth().verifyIdToken(idToken);
//log(“正确解码的ID令牌”,decodedIdToken);
req.user=decodedIdToken;
next();
返回;
}捕获(错误){
console.error(“验证Firebase ID令牌时出错:”,错误);
资源状态(403)。发送(“未授权”);
返回;
}
};

由于我无法重现您的环境,我不能保证这是100%工作的代码,但是我已经验证了大多数函数都能按预期工作

检查请求

这两组条件语句可以压缩在一起。检查请求的有效性并提取令牌可以表示为:(我们稍后会处理未经授权的案例)

hasToken
将检查请求
req
是否具有有效的授权头或
\u会话
cookie:

获取令牌

我们可以从标头或cookie中获取令牌:

生成403“未经授权”响应

我们也可以为此创建一个函数。它可以简单到:

但我们也可以将其分解为更小的可重用块:

因此,如果您想生成其他类型的响应,您可以:

验证令牌的有效性

我们可以使用功能性方法来尝试/捕获:

收回对
管理员的控制权

原始的
validateFireBaisedToken
函数依赖于一个不理想的外部变量
admin
。最好将其作为参数传递。为此,我们可以使用
咖喱

将所有内容组合在一起

使用的Ramda函数列表


非常感谢!我也在尝试,在未经授权之前,我已经得到了50%的补偿。它几乎匹配了90%,我使用了
除非
而不是
pathOr
。然而,我一直在苦苦挣扎,因为我不知道invpker、tryCatch和F。而且,你用
curry
来表示“admin”是非常棒的!我认为,我们应该调用unauthorized,而不是tryCatch中的
F
const verifyToken=async(admin,token)=>tryCatch(()=>admin.auth()。verifyIdToken(token),unauthorized(res));
const token = hasToken(req) ? getToken(req) : false;
const hasBearer = pipe(pathOr('', ['headers', 'authorization']), startsWith('Bearer'));
const hasSession = hasPath(['cookies', '__session']);
const hasToken = either(hasBearer, hasSession);
const getBearer = pipe(path(['headers', 'authorization']), replace('Bearer ', ''));
const getSession = path(['cookies', '__session']);
const getToken = either(getBearer, getSession);
const unauthorized = res => res.status(403).send('Unauthorized');
const status = invoker(1, 'status');
const send = invoker(1, 'send');
const unauthorized = pipe(status(403), send('Unauthorized'));
const notFound = pipe(status(404), send('Not Found'));
const serverError = pipe(status(500), send('Server Error'));
const verifyToken = async (admin, token) =>
  tryCatch(() => admin.auth().verifyIdToken(token), F)();
const validateFirebaseIdTokenFunction = curry(async (admin, req, res, next) => {
  // …
});
const {
  curry,
  either,
  F,
  hasPath,
  invoker,
  path,
  pathOr,
  pipe,
  replace,
  set,
  startsWith,
  tryCatch } = require('ramda');

const hasBearer = pipe(pathOr('', ['headers', 'authorization']), startsWith('Bearer'));
const getBearer = pipe(path(['headers', 'authorization']), replace('Bearer ', ''));
const hasSession = hasPath(['cookies', '__session']);
const getSession = path(['cookies', '__session']);
const hasToken = either(hasBearer, hasSession);
const getToken = either(getBearer, getSession);
const status = invoker(1, 'status');
const send = invoker(1, 'send');
const unauthorized = pipe(status(403), send('Unauthorized'));

const verifyToken = async (admin, token) =>
  tryCatch(() => admin.auth().verifyIdToken(token), F)();

const validateFirebaseIdTokenFunction = curry(async (admin, req, res, next) => {
  const token = hasToken(req) ? getToken(req) : false;
  const tokenVerified = token ? await verifyToken(admin, token) : false;
  return tokenVerified ? set('user', tokenVerified, req) && next() : unauthorized(res);
});

// This function now “waits” for the remaining arguments: `req`, `res` and `next`
const validateFirebaseIdToken = validateFirebaseIdTokenFunction(admin);