需要通过模式拼接来查找连接订阅的错误
Posted
技术标签:
【中文标题】需要通过模式拼接来查找连接订阅的错误【英文标题】:Need to find the error with connecting subscription with schema stitching 【发布时间】:2019-07-10 16:21:03 【问题描述】:我正在使用 apollo-server-express 作为 graphql 后端。我将只处理那里的突变,但我想通过自省的模式拼接来重定向hasura 上的查询和订阅。通过 apollo-server 到 hasura 的查询工作正常并返回预期的数据。
但订阅不起作用,我收到此错误:“预期可迭代,但没有为字段 subscription_root.users 找到一个”。
此外,服务器 hasura 正在接收事件:
但是 apollo-server 不喜欢 hasura 的回答。这不是我受此困扰的第一天,我无法理解问题所在。
在编辑器 hasura 订阅工作。
Link to full code
如果您需要任何其他信息,我很乐意提供给您。
import
introspectSchema,
makeExecutableSchema,
makeRemoteExecutableSchema,
mergeSchemas,
transformSchema,
FilterRootFields
from 'graphql-tools';
import HttpLink from 'apollo-link-http';
import nodeFetch from 'node-fetch';
import resolvers from './resolvers';
import hasRoleResolver from './directives';
import typeDefs from './types';
import WebSocketLink from 'apollo-link-ws';
import split from 'apollo-link';
import getMainDefinition from 'apollo-utilities';
import SubscriptionClient from 'subscriptions-transport-ws';
import * as ws from 'ws';
import OperationTypeNode from 'graphql';
interface IDefinitionsParams
operation?: OperationTypeNode,
kind: 'OperationDefinition' | 'FragmentDefinition'
const wsurl = 'ws://graphql-engine:8080/v1alpha1/graphql';
const getWsClient = function (wsurl: string)
const client = new SubscriptionClient(wsurl,
reconnect: true,
lazy: true
, ws);
return client;
;
const wsLink = new WebSocketLink(getWsClient(wsurl));
const createRemoteSchema = async () =>
const httpLink = new HttpLink(
uri: 'http://graphql-engine:8080/v1alpha1/graphql',
fetch: (nodeFetch as any)
);
const link = split(
( query ) =>
const kind, operation : IDefinitionsParams = getMainDefinition(query);
console.log('kind = ', kind, 'operation = ', operation);
return kind === 'OperationDefinition' && operation === 'subscription';
,
wsLink,
httpLink,
);
const remoteSchema = await introspectSchema(link);
const remoteExecutableSchema = makeRemoteExecutableSchema(
link,
schema: remoteSchema
);
const renamedSchema = transformSchema(
remoteExecutableSchema,
[
new FilterRootFields((operation, fieldName) =>
return (operation === 'Mutation') ? false : true; // && fieldName === 'password'
)
]
);
return renamedSchema;
;
export const createNewSchema = async () =>
const hasuraExecutableSchema = await createRemoteSchema();
const apolloSchema = makeExecutableSchema(
typeDefs,
resolvers,
directiveResolvers:
hasRole: hasRoleResolver
);
return mergeSchemas(
schemas: [
hasuraExecutableSchema,
apolloSchema
]
);
;
【问题讨论】:
【参考方案1】:我有同样的问题,不同的原因和解决方案。
我的订阅运行良好,直到我在 我的订阅解析器:
这是我的解析器的“订阅”部分:
Subscription:
mySubName:
resolve: (payload) =>
console.log('In mySubName resolver, payload:',payload)
return payload;
,
subscribe:() => pubSub.asyncIterator(['requestsIncomplete']),
// )
,
console.log 证明 resolve() 函数是使用结构良好的负载调用的(形状与我的 Schema 定义相同 - 特别是具有以 graphQL 订阅者命名的键的对象,指向一个数组(数组是一个可迭代的):
In mySubName resolver, payload: mySubName:
[ id: 41,
...,
,
...,
...
...
...
]
即使我返回的是同一个纯粹的对象,它也会导致错误expected Iterable, but did not find one for field "Subscription.mySubName"
当我将 resolve 函数全部注释掉时,订阅起作用了,这进一步证明了我的有效负载结构良好,正确的键指向一个可迭代对象。
我一定是误用了 resolve 字段。来自https://www.apollographql.com/docs/graphql-subscriptions/subscriptions-to-schema/
使用订阅字段时,也可以操作事件 在通过 GraphQL 执行引擎运行之前的有效负载。
在您的订阅附近添加解析方法并根据需要更改有效负载
所以我不确定如何正确使用该功能,特别是不知道要从中返回什么形状对象,但如上所述使用它会以您在问题中描述的相同方式破坏订阅。
我已经在使用 graphql-tools 4.0.0,我升级到 4.0.8 但没有任何区别。
【讨论】:
【参考方案2】:已通过安装 graphql-tools 第 4 版修复。结果编辑器甚至没有注意到我没有这种依赖关系,而是简单地获取了由其他软件包安装的 node_modules 的版本。问题出在版本 3.x 上。 Pull request 是修复错误的地方。
【讨论】:
以上是关于需要通过模式拼接来查找连接订阅的错误的主要内容,如果未能解决你的问题,请参考以下文章
ActiveMQ简单简绍(“点对点通讯”和 “发布订阅模式”)