Apollo条件数据源与初始化生命周期相关技术问题咨询
多用户条件化数据源接入解决方案
1. 基于Express请求条件化传入数据源的实现方式
完全可以实现。Apollo Server的上下文生成函数本身支持接收Express请求对象req,你不需要在全局dataSources()配置中预声明所有数据源,改为在上下文阶段挂载懒加载的数据源代理即可,只会实例化本次请求实际用到的数据源,不会造成资源浪费。
2. 向数据源传递令牌和凭证的正确时机
你遇到的initialize()时机过早的问题是普遍场景,正确的传递时机分两类:
- 标准
RESTDataSource:继续沿用willSendRequest方法取context中的凭证设置请求头即可,该方法在请求实际发送前执行,此时凭证已经写入context。 - 带专有客户端的自定义数据源:不要在
initialize()方法中执行客户端初始化逻辑,改为首次调用业务方法时懒加载初始化,此时transformer指令已经完成凭证写入,可直接从context读取有效凭证完成客户端实例化。
3. 自定义初始化函数的可行性
完全可行,这是适配你现有指令架构的最优方案:
- 给每个自定义数据源新增公开的
init(credentials)方法,专门用于接收凭证完成专有客户端的初始化,不要将该逻辑耦合到initialize()中。 - 你现有的transformer指令完成凭证写入context后,可直接根据当前请求的字段依赖,调用对应数据源的
init()方法传入凭证即可。 - 也可以给数据源添加自动初始化逻辑,在每个业务方法执行前先判断客户端是否完成初始化,未初始化则自动读取context中的凭证执行初始化,不需要手动调用。
代码示例
自定义Salesforce数据源示例
class SalesforceDataSource { #client = null; #context = null; // Apollo默认调用的初始化方法,仅存储context,不做客户端初始化 initialize({ context }) { this.#context = context; } // 自定义初始化方法,可由指令主动调用,也可内部自动调用 init(credentials) { if (this.#client) return; const jsforce = require('jsforce'); this.#client = new jsforce.Connection({ instanceUrl: credentials.instanceUrl, accessToken: credentials.accessToken }); } // 业务查询方法 async getAccount(accountId) { // 自动兜底初始化,避免指令漏调用 if (!this.#client) { this.init(this.#context.userCredentials.salesforce); } return this.#client.sobject('Account').retrieve(accountId); } }
上下文懒加载数据源配置示例
const server = new ApolloServer({ typeDefs, resolvers, // 关闭全局dataSources配置,改为上下文懒加载 // dataSources: () => ({ ... }) context: async ({ req }) => { // 第一步:解析用户身份 const userId = await verifyToken(req.headers.authorization); const context = { userId }; // 挂载懒加载数据源代理 context.dataSources = new Proxy({}, { get: (target, dsKey) => { if (target[dsKey]) return target[dsKey]; // 仅当请求用到对应数据源时才实例化 const DSClass = allDataSourceClasses[dsKey]; const dsInstance = new DSClass(); dsInstance.initialize({ context }); target[dsKey] = dsInstance; return dsInstance; } }); return context; } });
内容的提问来源于stack exchange,提问作者Random
相关产品推荐
相关产品推荐

