如何从KeystoneJS的Apollo Server端点自动获取完整GraphQL Schema?
如何通过KeystoneJS GraphQL端点自动获取Schema
当然可以!你完全能通过KeystoneJS暴露的GraphQL端点自动获取Schema,不用修改任何Keystone内部代码——这和GraphQL Playground下载Schema用的是同一个机制:GraphQL内省查询。这是GraphQL的标准特性,所有符合规范的服务(包括Keystone默认的GraphQL端点)都支持。
实现步骤
核心思路是向Keystone的GraphQL端点发送一个标准的内省查询,拿到结构化的Schema数据后,再转换成可读的SDL(Schema Definition Language)格式,也就是你从Playground下载的那种文本格式。
1. 发送内省查询请求
内省查询是一个特殊的GraphQL查询,它会请求服务端返回自身的Schema元数据。你可以用任何HTTP客户端(比如fetch、axios)发送POST请求到Keystone的GraphQL端点,带上这个查询。
2. 转换结果为SDL格式
拿到内省查询的返回结果后,用graphql官方包的工具函数把结构化数据转换成SDL字符串,之后就能自动处理那些Apollo Server不识别的定义了。
完整代码示例(Node.js)
const { printSchema, buildClientSchema } = require('graphql'); const fetch = require('node-fetch'); const fs = require('fs'); async function fetchAndCleanKeystoneSchema(keystoneEndpoint) { // 标准的GraphQL内省查询,覆盖所有Schema细节 const introspectionQuery = ` query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } } `; try { // 发送请求到Keystone GraphQL端点 const response = await fetch(keystoneEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', // 如果你的Keystone服务需要认证,添加对应的授权头 // 'Authorization': 'Bearer YOUR_AUTH_TOKEN' }, body: JSON.stringify({ query: introspectionQuery }) }); const result = await response.json(); if (result.errors) { throw new Error(`内省查询失败: ${JSON.stringify(result.errors)}`); } // 从内省数据构建Schema对象,再转换成SDL字符串 const rawSchema = buildClientSchema(result.data.__schema); let sdl = printSchema(rawSchema); // 这里添加你的自定义清理逻辑,移除Apollo Server不识别的定义 // 比如过滤Keystone生成的特定指令或类型 // 示例:移除某个自定义指令 // sdl = sdl.replace(/directive @someKeystoneDirective on .+/g, ''); // 将清理后的SDL写入文件,供你的Apollo Server使用 fs.writeFileSync('./cleaned-keystone-schema.graphql', sdl); console.log('Schema已成功获取并清理,保存到cleaned-keystone-schema.graphql'); return sdl; } catch (error) { console.error('处理Schema时出错:', error); throw error; } } // 调用示例,替换成你的Keystone GraphQL端点 fetchAndCleanKeystoneSchema('http://your-keystone-instance.com/api/graphql');
关键注意事项
- 认证处理:如果你的Keystone GraphQL端点启用了认证(比如JWT),记得在请求头中添加
Authorization字段,带上有效的凭证,否则会返回权限错误。 - 内省开关:大部分GraphQL服务默认开启内省查询,生产环境可能会禁用,但Keystone默认是开放的;如果遇到内省被禁用的情况,你需要在Keystone配置中开启它(不过你说不想修改Keystone内部,所以如果是默认配置就没问题)。
- 清理逻辑:你可以根据自己的需求扩展代码中的清理步骤,比如用字符串替换、AST解析工具(如
graphql-tools)来精准移除不需要的定义。
内容的提问来源于stack exchange,提问作者Cerulean
相关产品推荐
相关产品推荐

