0

我正在将apollo-server-express用于 graphql 后端。我将在那里只处理突变,但我想通过带有内省的模式拼接来重定向hasura上的查询和订阅。通过 apollo-server 到 hasura 的查询工作正常并返回预期数据。

但是订阅不起作用,我收到此错误:“预期可迭代,但未找到字段 subscription_root.users”。 来自控制台的错误

此外,服务器 hasura 正在接收事件: 来自 hasura 服务器的事件

但是 apollo-server 对 hasura 的回答表示不满。这不是我遭受这种痛苦的第一天,我无法理解问题所在。

在编辑 hasura 订阅工作。

链接到完整代码

如果您需要任何其他信息,我很乐意提供给您。

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
    ]
  });
};
4

2 回答 2

0

通过安装 graphql-tools 第 4 版修复。结果编辑器甚至没有注意到我没有这种依赖关系,而是简单地获取了由其他软件包安装的 node_modules 版本。问题出在版本 3.x 上。拉取请求是修复错误的地方。

于 2019-02-18T12:39:16.077 回答
0

我有同样的问题,不同的原因和解决方案。

我的订阅运行良好,直到我在订阅解析器中引入了“resolve”键:

这是我的解析器的“订阅”部分:

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/

使用 subscribe 字段时,还可以在通过 GraphQL 执行引擎运行事件负载之前对其进行操作。

在您的订阅附近添加解析方法并根据需要更改有效负载

所以我不确定如何正确使用该函数,特别是不知道要从中返回什么形状对象,但是如上所述使用它会以您在问题中描述的相同方式破坏订阅。

我已经在使用 graphql-tools 4.0.0,我升级到了 4.0.8,但没有任何区别。

于 2020-06-07T22:06:50.047 回答