Apollo Server 3如何为GraphQL响应添加元数据(装饰响应)
在Apollo Server 3中返回额外元数据的两种实现方案
方案一:根响应外层添加metadata(对应格式一)
Apollo Server 3 内置的 formatResponse 钩子是修改响应结构的官方方案,完全匹配你在根响应外层加metadata的需求:
- 步骤1:在Context中存储元数据
在创建ApolloServer实例时,通过context函数生成或传入需要返回的元数据(比如请求ID、时间戳等):
const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { // 根据请求上下文生成元数据 const metadata = { requestId: req.headers['x-request-id'] || crypto.randomUUID(), timestamp: Date.now() }; return { metadata }; }, // 步骤2:用formatResponse修改响应结构 formatResponse: (response, { context }) => { // 组合原响应数据与元数据,保留错误字段(如果有) const formattedResponse = { metadata: context.metadata, data: response.data }; if (response.errors) { formattedResponse.errors = response.errors; } return formattedResponse; }, });
启动服务后,客户端收到的响应就会是你需要的格式一结构。
方案二:在data对象内添加metaData(对应格式二)
这种方案需要调整Schema结构,让元数据成为Query类型的一个字段,或者通过解析器包装自动注入:
方式1:显式添加Query字段(推荐,符合GraphQL规范)
- 修改Schema
在根Query类型中新增metaData字段,并定义对应的元数据类型:
type MetaData { requestId: String! timestamp: Int! } type Query { typeOne: TypeOne! typeTwo: TypeTwo! metaData: MetaData! }
- 编写元数据解析器
从Context中取出预存的元数据返回:
const resolvers = { Query: { typeOne: () => { /* 原typeOne解析逻辑 */ }, typeTwo: () => { /* 原typeTwo解析逻辑 */ }, metaData: (_, __, { metadata }) => metadata, }, };
客户端只需在查询中包含metaData字段,就能在返回的data对象中拿到它,完全符合格式二的结构。
方式2:自动注入metaData(无需客户端显式查询)
如果要求必须自动返回metaData,无需客户端额外查询,可以通过包装根Query解析器实现:
// 定义解析器包装函数,自动合并元数据到返回结果 const wrapRootResolver = (originalResolver) => async (parent, args, context, info) => { const resolveResult = await originalResolver(parent, args, context, info); // 仅当返回结果为对象时合并元数据 if (typeof resolveResult === 'object' && resolveResult !== null) { return { ...resolveResult, metaData: context.metadata }; } return resolveResult; }; // 给所有根Query字段应用包装器 Object.keys(resolvers.Query).forEach(fieldName => { resolvers.Query[fieldName] = wrapRootResolver(resolvers.Query[fieldName]); });
注意:这种方式要求所有根Query字段返回对象类型,否则会出现结构异常,仅适合特定业务场景。
内容的提问来源于stack exchange,提问作者Robert Moskal
相关产品推荐
相关产品推荐

