我了解如何在创建GraphQL服务器时设置上下文对象,例如
const app = express();
app.use(GRAPHQL_URL, graphqlExpress({
schema,
context: {
foo: 'bar'
},
}));
以便在处理传入请求时将上下文对象传递给我的解析器。
但是,当订阅者触发解析器时,我没有看到此上下文对象(即客户端订阅GraphQL订阅,并定义订阅触发时要发送给它们的数据的形状);在这种情况下,上下文似乎是一个空对象。
在PubSub.publish()调用之后调用解析器时,有没有办法确保我的上下文对象设置正确?
答案 0 :(得分:0)
我猜你正在使用包subscription-transport-ws
。在这种情况下,可以在不同的执行步骤中添加上下文值。
见API。两种可能的情况
如果您有某种身份验证。您可以在onConnect
执行步骤中在上下文中添加查看器。这是在第一次连接到websocket时完成的,并且不会改变,直到连接关闭并再次打开。请参阅example。
如果您想更动态地添加上下文,可以在执行步骤之前添加一种中间件。它可能如下所示:
const middleware = (args) => new Promise((resolve, reject) => {
const [schema, document, root, context, variables, operation] = args;
context.foo = "bar"; // add something to context
resolve(args);
})
subscriptionServer = SubscriptionServer.create({
schema: executable.schema,
subscribe,
execute: (...args) => middleware(args).then(args => {
return execute(...args);
})
}, {
server: websocketServer,
path: "/graphql",
}, );

答案 1 :(得分:0)
这是我的解决方法:
proc getval {argc argv} {
global val
for {set i 0} {$i < $argc} {incr i} {
set arg [lindex $argv $i]
if {[string index $arg 0] eq "-"} {
set val([string range $arg 1 end]) [lindex $argv [incr i]]
}
}
}
const server = new ApolloServer({
typeDefs,
resolvers,
context: contextFunction,
introspection: true,
subscriptions: {
onConnect: (
connectionParams: IWebSocketConnectionParams,
webSocket: WebSocket,
connectionContext: ConnectionContext,
) => {
console.log('websocket connect');
console.log('connectionParams: ', connectionParams);
if (connectionParams.token) {
const token: string = validateToken(connectionParams.token);
const userConnector = new UserConnector<IMemoryDB>(memoryDB);
let user: IUser | undefined;
try {
const userType: UserType = UserType[token];
user = userConnector.findUserByUserType(userType);
} catch (error) {
throw error;
}
const context: ISubscriptionContext = {
// pubsub: postgresPubSub,
pubsub,
subscribeUser: user,
userConnector,
locationConnector: new LocationConnector<IMemoryDB>(memoryDB),
};
return context;
}
throw new Error('Missing auth token!');
},
onDisconnect: (webSocket: WebSocket, connectionContext: ConnectionContext) => {
console.log('websocket disconnect');
},
},
});
方法来传递解析器的上下文参数,如下所示:pubsub.publish
addTemplate: (
__,
{ templateInput },
{ templateConnector, userConnector, requestingUser }: IAppContext,
): Omit<ICommonResponse, 'payload'> | undefined => {
if (userConnector.isAuthrized(requestingUser)) {
const commonResponse: ICommonResponse = templateConnector.add(templateInput);
if (commonResponse.payload) {
const payload = {
data: commonResponse.payload,
context: {
requestingUser,
},
};
templateConnector.publish(payload);
}
return _.omit(commonResponse, 'payload');
}
},
解析器Subscription
方法如下:subscribe
Subscription: {
templateAdded: {
resolve: (
payload: ISubscriptionPayload<ITemplate, Pick<IAppContext, 'requestingUser'>>,
args: any,
subscriptionContext: ISubscriptionContext,
info: any,
): ITemplate => {
return payload.data;
},
subscribe: withFilter(templateIterator, templateFilter),
},
},
如您所见,现在我们从async function templateFilter(
payload?: ISubscriptionPayload<ITemplate, Pick<IAppContext, 'requestingUser'>>,
args?: any,
subscriptionContext?: ISubscriptionContext,
info?: any,
): Promise<boolean> {
console.count('templateFilter');
const NOTIFY: boolean = true;
const DONT_NOTIFY: boolean = false;
if (!payload || !subscriptionContext) {
return DONT_NOTIFY;
}
const { userConnector, locationConnector } = subscriptionContext;
const { data: template, context } = payload;
if (!subscriptionContext.subscribeUser || !context.requestingUser) {
return DONT_NOTIFY;
}
let results: IUser[];
try {
results = await Promise.all([
userConnector.findByEmail(subscriptionContext.subscribeUser.email),
userConnector.findByEmail(context.requestingUser.email),
]);
} catch (error) {
console.error(error);
return DONT_NOTIFY;
}
//...
return true;
}
和HTTP请求{{1}中获得了订阅用户(他们与graphql Web服务器建立了WebSocket连接)和HTTP请求用户(将变异发送到graphql Web服务器) }。
然后,如果subscriptionContext
函数的返回值正确,则可以完成其余工作,然后WebSocket将推送消息以context
订阅用户,否则不会。
此templateFilter
函数将被多次执行,具体取决于订阅用户的数量,这意味着它是可迭代的。现在,您将获得此功能中的每个订阅用户,并执行业务逻辑来确定是否将WebSocket消息推送到订阅用户(客户端)。
文章: