中间件(Middleware)
中间件是一种函数,它介入了解析函数的处理流程。它提供了一种在请求和响应流程中插入逻辑的方式,以便在发送响应之前或在请求处理之前执行代码。
GQLoom
的中间件遵循了 Koa 的洋葱式中间件模式。
定义中间件
中间件是一个函数,它将在调用时被注入 options
对象作为参数,options
包含以下属性:
outputSilk
: 输出丝线,包含了当前正在解析字段的输出类型;parent
: 当前字段的父节点,相当于useResolverPayload().root
;parseInput
: 用于获取或修改当前字段的输入;type
: 当前字段的类型,其值为query
,mutation
,subscription
或field
;next
: 用于调用下一个中间件的函数;
options
还可以直接作为 next
函数使用。
另外,我们还可以通过 useContext()
和 useResolverPayload()
获取到当前解析函数的上下文以及更多信息。
一个最基础的中间件函数如下:
接下来,我们将介绍一些常见的中间件形式。
错误捕获
在使用 Valibot 或 Zod 等库进行输入验证时,我们可以在中间件中捕获验证错误,并返回自定义的错误信息。
验证输出
在 GQLoom
中,默认不会对解析函数的输出执行验证。但我们可以通过中间件来验证解析函数的输出。
让我们尝试使用这个中间件:
在上面的代码中,我们对 hello
查询的输出添加了 v.minLength(10)
的要求,并在解析函数中添加了 outputValidator
中间件。
我们还在 weave
中添加了一个全局中间件 ValibotExceptionFilter
。
当我们进行以下查询时:
将会得到类似如下的结果:
如果我们调整输入,使返回的字符串长度符合要求:
将会得到没有异常的响应:
鉴权
对用户的权限进行校验是一个常见的需求,我们可以通过中间件来轻易实现。
考虑我们的用户有 "admin"
和 "editor"
两种角色,我们希望管理员和编辑员分别可以访问自己的操作。
首先,我们实现一个 authGuard
中间件,用于校验用户的角色:
在上面的代码中,我们声明了一个 authGuard
中间件,它接受一个角色参数,并返回一个中间件函数。
中间件函数会检查用户是否已经认证,并且是否具有指定的角色,如果不符合要求,则抛出一个 GraphQLError
异常。
我们可以为不同的解析器应用不同的中间件:
在上面的代码中,我们为 adminResolver
和 editorResolver
分别应用了 authGuard
中间件,并指定了不同的角色。这样,只有具有相应角色的用户才能访问对应解析器内的操作。
日志
我们也可以通过中间件来实现日志记录功能。例如,我们可以创建一个 logger
中间件,用于记录每个字段解析函数的执行时间:
缓存
我们可以通过中间件来实现缓存功能。例如,我们可以创建一个 cache
中间件,用于缓存每个查询的解析结果:
修改输入
我们可以通过中间件来修改请求输入:
使用中间件
GQLoom 能够在各种范围内应用中间件,包括解析函数、解析器局部中间件和全局中间件。
解析函数中间件
我们可以在解析函数中直接使用中间件,只需要在构造时使用 use
方法,例如:
解析器局部中间件
我们也可以在解析器级别应用中间件,这样中间件将对解析器内的所有操作生效。
只需要使用 use
方法为解析器构添加 middlewares
:
全局中间件
为了应用全局中间件,我们需要在 weave
函数中传入中间件字段,例如:
根据操作类型应用中间件
我们可以为中间件指定在哪些操作类型上生效。
Middleware.operations
是一个字符串数组,用于指定中间件在哪些操作类型上生效,可选值为:
"query"
;"mutation"
;"subscription"
;"field"
;"subscription.resolve"
;"subscription.subscribe"
;
Middleware.operations
的默认值为 ["field", "query", "mutation", "subscription.subscribe"]
。