javascript - 这个解析器扩展功能是如何工作的?

标签 javascript graphql apollo-server

我需要帮助解释一段代码。

我一直在尝试学习如何使用 jwt 以及返回 token 和刷新 token 对用户进行身份验证。

这是一次有趣的旅程,我遇到了这个 repository据我所知,用户添加了一个扩展/链函数,它结合了多个 graphql 解析器:

// I don't understand this function
const createResolver = (resolver) => {
  const baseResolver = resolver;
  baseResolver.createResolver = (childResolver) => {
    const newResolver = async (parent, args, context, info) => {
      await resolver(parent, args, context, info);
      return childResolver(parent, args, context, info);
    };
    return createResolver(newResolver);
  };
  return baseResolver;
};

export const requiresAuth = createResolver((parent, args, context) => {
  if (!context.user || !context.user.id) {
    throw new Error('Not authenticated');
  }
});

export const requiresAdmin = requiresAuth.createResolver((parent, args, context) => {
  if (!context.user.isAdmin) {
    throw new Error('Requires admin access');
  }
});

它是这样使用的:

Query: { 
    getBook: requiresAuth.createResolver((parent, args, { models }, info) =>
       // do something fun
    ),
}

我不明白 createResolver 函数,我想问的是这是否是某种编程范例,其中有一些我可以阅读并更好地理解的文章。

谷歌搜索我确实找到了 graphql-resolvers 据我所知做同样的事情但在这种情况下,我需要安装另一个我想避免但同时时间,我不想使用我不完全理解的功能。

编辑:

我对函数的理解/我认为我理解的:

通过调用一个函数将多个函数链接在一起,然后在该函数内部传入一个新函数:requiresAuth.createResolver 在函数本身内部,我无法弄清楚。 我们得到一个新变量 baseResolver 我们链接一个新的 createResolver 然后我们递归地调用父函数。

我猜我无法理解这个流程。

最佳答案

我冒昧地重命名了一些东西,因为现有的名称非常困惑。

const augment = (resolver) => {
  resolver.add = (nextResolver) => {
    const wrapper = async (parent, args, context, info) => {
      await resolver(parent, args, context, info)
      return nextResolver(parent, args, context, info)
    }
    return augment(wrapper)
  }
  return resolver
}

在方法的每一步都将 .add 方法添加到返回的函数中,以启用链接,如下所示:

augment(resolver1).add(resolver2).add(resolver3)...

每次调用 .add 时,都会创建一个新的异步 lambda 函数(wrapper)。 wrapper 关闭 resolvernextResolver。最终运行时,wrapper会调用resolver,等待结果,然后调用nextResolver,返回结果。

wrapper 然后传递给 augment 以向其添加 .add 函数(以启用链接)。这个新的 add 函数关闭提供给 augment 的参数(即 wrapper)。返回增强的 wrapper 函数。

因此,当随后调用 .add 时,resolver 参数是调用 .add< 的 wrapper 函数 在以前的解析器上。所以:

await resolver(parent, args, context, info)
return nextResolver(parent, args, context, info)

...将等待先前创建的wrapper 函数,然后调用最新的nextResolver

通过这种方式,对 .add 的连续调用构建了一个异步函数链。

当您想要运行链时,您可以简单地调用返回的函数,忽略其上的 .add 属性。

请注意,每个解析器都会传递相同的参数,以避免用户担心将它们传递到链中。

函数可以重写为:

const augment = (resolver) => {
  resolver.add = (nextResolver) => 
    augment((...args) => 
      resolver(...args)
        .then(() => nextResolver(...args)))
  return resolver
}

...或者:

const inSequence = (resolvers) => 
    (...args) => 
        resolvers.reduce((acc, el) => 
            acc.then(() => el(...args)), Promise.resolve())

const getBook = inSequence([auth, admin, getBookResolver])
const query = { getBook }

...或者:

const inSequence = (resolvers) => 
    async (...args) => {
        for(let el of resolvers) {
            await el(...args)
        }
    }
const getBook = inSequence([auth, admin, getBookResolver])
const query = { getBook }

关于javascript - 这个解析器扩展功能是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60951440/

相关文章:

javascript - 多个显示隐藏切换与 div 滑出

java - 如何在以正确方式获取的事务之外初始化延迟加载的集合?

react-native - React Native、GraphQL、Apollo - 如何创建批量插入突变

php - 发送回响应字符串以在 jQuery 的 ajax 函数中使用

javascript - 使用 google API 和 javascript 的 PHP 项目 : Inherited Mess

node.js - Sequelize 和 Apollo 服务器 : map findAll "sequelize.literal" field to an Apollo schema field

reactjs - 我应该在哪个端口上运行 GraphQL 服务器?

javascript - Apollo 服务器 RESTDataSource - 接受自签名证书

apollo-server - 是否可以为 Apollo Server 附带的 GraphQL Playground 定义 HTTP header ?

javascript - AngularJS - 如何缓存服务的 ajax 结果以在 Controller 中重用