GraphQL解析器中间件的详细指南

248 阅读2分钟

GraphQL解析器用于将GraphQL查询解析为实际数据。在这个GraphQL教程中,你将学习如何为这些解析器设置一个GraphQL中间件,以处理授权和权限。下面的代码片段显示了一个带有参数的GraphQL解析器,它在数据库中创建了一个新实体:

export default {
  Mutation: {
    createFreeCourse: async (
      parent,
      { courseId, bundleId },
      { me }
    ) => {
      await createCourse({
        uid: me.uid,
        courseId,
        bundleId,
        amount: 0,
        paymentType: 'FREE',
      });

      return true;
    },
  },
};

在这种情况下,一个用户创建了一个具有GraphQL突变的课程,称为createFreeCourse 。它从解析器的函数参数中获取一些参数,也从解析器的上下文中获取用户本身。现在,如果一个用户没有经过认证,就不应该能够访问数据库。

export default {
  Mutation: {
    createFreeCourse: async (
      parent,
      { courseId, bundleId },
      { me }
    ) => {
      if (!me) {
        return new Error('Not authenticated as user.');
      }

      await createCourse({
        uid: me.uid,
        courseId,
        bundleId,
        amount: 0,
        paymentType: 'FREE',
      });

      return true;
    },
  },
};

对于一个有很多解析器的大型GraphQL服务器来说,这种授权检查会发生很长时间。为了摆脱这种手工工作,我们可以在另一个文件中用graphql-resolvers 包为这个和所有其他解析器写一个中间件函数。

import { skip } from 'graphql-resolvers';

export const isAuthenticated = (parent, args, { me }) =>
  me ? skip : new Error('Not authenticated as user.');

毕竟,这个中间件函数只是另一个GraphQL解析器。我们可以在我们以前的解析器中导入它,并将它与graphql-resolvers 包结合起来,成为一个受保护的解析器(也称为防护解析器)。

import { combineResolvers } from 'graphql-resolvers';

import { isAuthenticated } from './middleware/isAuthenticated';

export default {
  Mutation: {
    createFreeCourse: combine(
      isAuthenticated,
      async (parent, { courseId, bundleId }, { me }) => {
        await createCourse({
          uid: me.uid,
          courseId,
          bundleId,
          amount: 0,
          paymentType: 'FREE',
        });

        return true;
      }
    ),
  },
};

每次这个GraphQL解析器运行时,它都会在运行实际的解析器之前进行认证检查。让我们用另一个权限检查再进一步。首先,定义另一个解析器中间件函数:

import { skip } from 'graphql-resolvers';

export const isFreeCourse = (parent, { courseId, bundleId }) => {
  const price = getPrice(courseId, bundleId);

  return price === 0
    ? skip
    : new Error('This course is not for free.');
};

其次,将它用于你的实际解析器:

import { combineResolvers } from 'graphql-resolvers';

import { isAuthenticated } from './middleware/isAuthenticated';
import { isFreeCourse } from './middleware/isFreeCourse';

export default {
  Mutation: {
    createFreeCourse: combine(
      isAuthenticated,
      isFreeCourse,
      async (parent, { courseId, bundleId }, { me }) => {
        await createCourse({
          uid: me.uid,
          courseId,
          bundleId,
          amount: 0,
          paymentType: 'FREE',
        });

        return true;
      }
    ),
  },
};

正如你所看到的,它并没有以两个组合的解析器结束。你可以在堆栈中添加更多的权限和授权处理,以获得更详细的权限。此外,你可以把它们作为独立的或组合的解析器进行测试。