PostGraphile v4 插件开发makeProcessSchemaPlugin 原理与实战【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystalmakeProcessSchemaPlugin 是 PostGraphile v4graphile-utils中用于在 GraphQL Schema 构建完成后对最终 Schema 进行二次处理的官方插件助手。在基于 PostGraphile 构建 API 服务时你可能需要在 Schema 生成之后执行 SDL 导出、接入第三方工具、持久化查询校验或 Schema 拼接等操作本文将以 makeProcessSchemaPlugin 官方文档 为主体结合仓库源码与单元测试讲解该插件的用法、底层实现、加载方式与注意事项。读完本文你将掌握如何在 PostGraphile v4 中编写自己的 Schema 处理插件并将其接入 CLI 或库模式运行。一、它解决什么问题PostGraphile 的 Schema 生成器由一系列 Graphile Engine 插件组成参见 extending.mdx 对 Schema 插件体系的说明。官方文档明确说明makeProcessSchemaPlugin提供了一种在 Schema 构建完成之后处理它的方式a way of processing the schema after its built典型场景包括将 Schema 的 SDLSchema Definition Language打印到文件将 Schema SDL 上传到某个网络服务用生成的 Schema 检查你的持久化查询persisted queries是否仍然有效依据自定义逻辑校验 Schema用 Mock 版本或派生版本替换原 Schema例如与其他 Schema 做拼接 stitching与第三方库集成。简而言之这个插件是 PostGraphile 的 Schema 生命周期中「最后一公里」的挂钩点所有其他插件扩展字段、修改命名、调整解析方式、改变可空性等都处理完毕后它拿到最终产物做收尾工作。二、API 与基本约定插件只接受一个参数Schema 处理函数。该函数会被调用并传入生成的GraphQLSchema且必须返回一个 Schema返回同一个 Schema适用于只读操作或直接对传入 Schema 进行原地修改的场景返回另一个 Schema适用于派生/替换场景例如用拼接后的 Schema 替换原 Schema。在graphile-utils源码中其完整实现只有不到 30 行见 makeProcessSchemaPlugin.tstype ProcessSchemaFunction (schema: GraphQLSchema) GraphQLSchema; export function processSchema( callback: ProcessSchemaFunction, ): GraphileConfig.Plugin { return { name: ProcessSchemaPlugin_${counter}, version: 0.0.0, schema: { hooks: { finalize: { callback, }, }, }, }; } /** deprecated use processSchema */ export const makeProcessSchemaPlugin processSchema;从源码可以看出两点关键信息makeProcessSchemaPlugin与processSchema是同一个函数前者带有deprecated标记是后者的别名。二者均从 graphile-utils 的入口 index.ts 导出export { makeProcessSchemaPlugin, processSchema } from ./makeProcessSchemaPlugin.ts。因此在 PostGraphile v4 中两种写法都可用新代码建议直接使用processSchema。底层是schema.finalize钩子每次调用都会创建一个名为ProcessSchemaPlugin_${counter}的自增命名插件并把处理函数挂到schema.hooks.finalize上。这正是该插件能够在 Schema 构建完成后介入的根本原因。三、底层原理finalize 钩子与 Schema 构建流程为了理解处理函数何时被调用需要看一下 Schema 构建的收尾阶段。在 SchemaBuilder.ts 中Schema 构建的流程是先构造临时 Schema然后通过applyHooks(finalize, tempSchema, build, finalizeContext, Finalizing GraphQL schema)触发所有插件的finalize钩子最后再对返回的 Schema 执行validateSchema校验const schema tempSchema ? this.applyHooks( finalize, tempSchema, build, finalizeContext, Finalizing GraphQL schema, ) : tempSchema; if (!schema) { throw new Error(Schema generation failed); } const validationErrors validateSchema(schema); if (validationErrors.length) { throw new AggregateError( validationErrors, Schema construction failed due to ${ validationErrors.length } validation failure(s). First failure was: ${String( validationErrors[0], )}, ); }由此可以得出以下可验证的推论makeProcessSchemaPlugin的处理函数在所有其他插件完成构建后、Schema 正式返回给用户前执行若处理函数返回了非空 Schema该结果会继续参与validateSchema校验——所以你在处理函数中引入的派生 Schema 或修改也会被 PostGraphile 做合法性检查若返回非法 Schema 会触发 Schema construction failed 错误finalize是官方为「Schema 收尾」设计的标准钩子除本插件外PostGraphile 自带的 MinifySchemaPluginSchema 压缩等内置插件也使用finalize(schema, build)实现类似的后处理可见这是 schema 级插件的通用机制。四、实战示例4.1 基础用法把处理函数写成插件官方文档给出的最小示例——将第三方增强逻辑应用到生成的 Schema 上const { makeProcessSchemaPlugin } require(graphile-utils); module.exports makeProcessSchemaPlugin((schema) { return addThirdPartyEnhancementsToSchema(schema); });其中addThirdPartyEnhancementsToSchema可以是任意处理函数。注意它必须返回 Schema如果只是做只读操作或直接原地修改原样返回schema即可如果生成了新 Schema则返回新 Schema。4.2 Schema 拼接用拼接结果替换当前 Schema官方文档同时演示了如何用该插件将拼接stitching后的 Schema 替换原 Schema并直接在 PostGraphile 服务器内运行const { makeProcessSchemaPlugin } require(graphile-utils); module.exports makeProcessSchemaPlugin((schema) { return stitchOtherSchemasInto(schema); });此时 PostGraphile 对外提供的将是stitchOtherSchemasInto(schema)的返回值而不是原始的 PostGraphile Schema。这与 4.1 的本质区别在于返回的是「另一个 Schema」而不是「同一个 Schema」。4.3 扩展导出 Schema SDL 到文件将处理函数与文件输出结合即可实现「Schema 构建后自动导出 SDL」。PostGraphile v5 的 process-schema.md 中给出了借助graphile-export将 Schema 导出为可执行代码的类似思路v4 中可以同样把 SDL 打印逻辑放进回调const { makeProcessSchemaPlugin } require(graphile-utils); const { printSchema } require(graphql); const fs require(fs); module.exports makeProcessSchemaPlugin((schema) { // 只读操作打印/导出 SDL然后原样返回 schema fs.writeFileSync( ${process.cwd()}/schema.graphql, printSchema(schema), ); return schema; });这类只读用法不会影响 PostGraphile 实际使用的 Schema适合 CI、文档生成、代码生成等辅助场景。五、如何加载该插件makeProcessSchemaPlugin返回的是一个标准的 Graphile 插件对象因此与其他 PostGraphile 插件的加载方式完全一致详见 extending.mdx 的 Loading Plugins 章节。CLI 方式通过--append-plugins加载# 本地文件注意文件必须通过 module.exports 导出插件函数 postgraphile \ --append-plugins pwd/my-process-schema-plugin.js \ -c postgres:///mydb # 或加载 npm 包形式的插件 postgraphile \ --append-plugins postgraphile-plugin-connection-filter \ -c postgres:///mydb--append-plugins接受逗号分隔的模块描述符可以是某个 JS 文件的绝对路径也可以是 npm 模块名若插件不是通过module.exports function MyPlugin(...)默认导出则需在模块名后加冒号和导出名例如--append-plugins /path/to/local/module.js:MyPlugin。库模式通过appendPlugins选项加载const MyProcessSchemaPlugin require(./my-process-schema-plugin); app.use( postgraphile(process.env.DATABASE_URL, app_public, { appendPlugins: [ MyProcessSchemaPlugin, /* 其他插件 */ ], graphiql: true, }), );库模式下你自行负责 import 插件函数并把函数数组传给appendPlugins。六、注意事项与坑官方文档针对该插件特别提醒了两类问题1. 第三方工具对 Schema 的可变性假设一些第三方工具会直接修改现有的 GraphQL Schema 对象这很可能引发问题例如影响 Schema 复用、缓存或并发请求。官方建议只使用将 GraphQL Schema 视为不可变immutable的工具如果实在无法避免则构建一个「牺牲用 Schema」sacrificial schema让它委托给 PostGraphile Schema 但允许被第三方工具修改。2. 异步操作的局限性v4 同样适用虽然该提示在 v5 文档process-schema.md 中的 info 框中有更明确的表述但 v4 的实现完全一致finalize钩子的回调是同步的。如果你需要做异步工作如上传 SDL 到网络服务必须自行处理可能发生的错误并且要知道异步工作的结果不会影响插件返回值也不会影响服务器实际使用的 Schema。换言之异步场景只适合「触发一次性的外部副作用」不适合用它来改变最终 Schema。另外v5 文档还提到graphql-shield这类传统 resolver 工具与 Grafast plan resolver 不兼容因为 PostGraphile v5 起的 Schema 使用 Grafast的 plan resolver 体系v4 中若集成类似工具同样应优先考虑「派生 Schema 委托」而非原地改写。七、测试验证这个插件真的这样工作吗仓库中 makeProcessSchemaPlugin.test.ts 用三个用例逐一验证了上述行为可以作为理解该插件语义的权威参考Gets passed the final schema用jest.fn构造 spy断言处理函数收到的是最终构建完成的 Schema且返回值与最终 Schema 相等——验证「传入的是最终产物」Can replace the schema处理函数返回一个全新的simpleSchema断言最终 Schema 等于被替换后的新 Schema——验证「返回别的 Schema 即可整体替换」Can tweak the schema处理函数直接修改_schema.getQueryType().description MODIFIED DESCRIPTION并原样返回快照断言修改生效——验证「原地修改 原样返回」的用法可行。该测试还展示了插件在buildSchema中与其他内置插件CommonTypesPlugin、QueryPlugin、MutationPlugin等并列使用的写法如果你要编写自己的 Schema 插件并跑单元测试这份测试文件本身就是很好的模板。八、小结makeProcessSchemaPlugin别名processSchema是 PostGraphile v4 提供的 Schema 后处理入口本质是把一个(schema) schema的函数挂到schema.finalize钩子上处理函数必须返回 Schema只读/原地修改返回原 Schema派生/拼接返回新 Schema回调在 Schema 构建完成、validateSchema校验之前同步执行异步工作不会影响最终 Schema加载方式与普通插件一致CLI 用--append-plugins库模式用appendPlugins数组集成第三方工具时优先选择不可变 Schema 的工具必要时构建「牺牲 Schema」做委托仓库内的单元测试makeProcessSchemaPlugin.test.ts与构建源码SchemaBuilder.ts完整印证了上述全部行为可作为深入学习的起点。【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
