片段不能在此处传播,因为 "X" 类型的对象永远不会是 "Y" 类型的对象

Fragment cannot be spread here as objects of type "X" can never be of type "Y"

在这种情况下,类型 "X" 是 Application,类型 "Y" 是类型 "Node" - 我明白了 为什么会这样,但我对 Relay 的理解不足以理解如何修复它。中继生成的查询是

query {
    node(id: $some_id) {
        ...F0
    }
}

fragment F0 on Application {
    ...
}

我的架构看起来像

query {
    application { 
        /* kind of a generic endpoint for fetching lists, etc */
        invites(token: $token) {
            name
        }
    }
    viewer { /* the current user */ }
}

我正在尝试从会话外部获取特定邀请(viewernull)。

我试过了

const application = Relay.QL`query { application }`
...
<Route ... queries={{ application }}/>
...
Relay.createContainer(Component, {
    initialValues: { token: null },
    fragments: {
        application: () => {
            fragment on Application {
                invites(token: $token) {
                    ...
                }
            }
        }
    }
})

这给了我错误

片段 "F0" 不能在这里传播,因为类型 "Node" 的对象永远不能是类型 "Application" - 或者类似的东西。

我有点困惑,因为如果我要编写原始查询并 运行 直接通过 GraphQL

query {
    application {
        invites(token: "asdasdasd") {
            edges {
                node {
                    name
                }
            }
        }
    }
}

它给了我想要的东西...

在后端,我的图表定义如下

export const Application = new GraphQLObjectType({
  name: 'Application',
  fields: () => ({
    id: {
      type: GraphQLString,
      resolve: () => 'APPLICATION_ID'
    },
    invites: {
        type: InviteConnectionType,
        args: connectionArgs,
        resolve: (application, args) => {
            ...
        } 
    }
  })
})

export default new GraphQLSchema({
  query: new GraphQLObjectType({
  name: 'query',
  fields: {
    node: nodeField,
    application: {
      type: Application,
      resolve: (root, args, ctx) => {
        return Promise.resolve({})
      }
    }
  }
})

我一直在看 this and some issues on the Relay github 这样的问题,但我不清楚我应该如何实施 nodeInterface

编辑:当前nodeInterface代码的短-长是

export const {
  nodeInterface,
  nodeField
} = nodeDefinitions(
  (globalId) => {
    const { type, id } = fromGlobalId(globalId)
    return db[type].findById(id)
  },
  (obj) => {
    const name = obj.$modelOptions.name.singular
    return types[name]
  }
)

应用程序不是数据库模型,但是,它只是一个用于获取数据的通用接口。我已经尝试检查是否 type === 'Application',并返回 null(虽然我明白为什么这不起作用),返回 Application(GraphQLObject),但这不起作用......不真的很确定从那里去哪里。

  • 您需要为 GraphQL 自动生成唯一的全局 ID 您要重新获取的类型。
  • nodeInterface 你告诉 GraphQL 如何将id映射到对应的GraphQL对象。
  • 通过给定的服务器端对象nodeInterface识别GraphQL类型。

下面是应用程序的简化示例:

// nodeInterface.
var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);

    // The mapping from globalId to actual object id and type.
    console.log('globalId:', id);
    console.log('type:', type);

    if (type === 'Application') {
      // getApplication is your db method to retrieve Application object.
      // With id you could also retrieve a specific db object.
      return getApplication();
    } else {
      return null;
    }
  },
  (obj) => {
    // Note that instanceof does an identity check on the prototype object, so it can be easily fooled.
    if (obj instanceof Application) {
      return ApplicationType;
    } else {
      return null;
    }
  },
);

// Application.
export const ApplicationType = new GraphQLObjectType({
  name: 'Application',
  fields: () => ({
    // Auto-generated, globally defined id.
    id: globalIdField('Application'),
    _id: {
      type: GraphQLString,
      resolve: () => 'APPLICATION_ID'
    },
    invites: {
        type: InviteConnectionType,
        args: connectionArgs,
        resolve: (application, args) => {
            ...
        } 
    }
  }),
  // Declaring nodeInterface.
  interfaces: [nodeInterface]
});

请注意,在初始提取期间 nodeInterface 甚至不会执行,因此如果 nodeInterface 没有返回任何内容,则在初始提取时不会出现错误。如果这没有意义或者您仍在努力,您可以 post 一个 link 到回购协议,我会调查它。

要对此进行更新,我走在正确的道路上。

目前的 nodeDefinitions 我只是需要一点额外的:

nodeDefinitions(
  (globalId) => {
    const { type, id } = fromGlobalId(globalId)

    if (type === 'Application') {
      return Promise.resolve(Application)
    }

    return db[type].findById(id)
  },
  (obj) => {
    if (obj.$modelOptions) {
      /* sequelize object */
      const name = obj.$modelOptions.name.singular
      return types[name]
    } else if (obj.name === 'Application') {
      return Application
    }

    return null
  }
)

我不确定这是否是最好的方法,但它似乎可以解决问题。要点是,如果我想要 returned 的节点类型是 Application,我 return GraphQL 对象 - { ... name: "Application" ... } 我们将使用 name 字段从下一步(nodeDefinitions 中的第二个回调)到只是重新 return Application。我认为您可以 return 一个 "custom" 对象或其他对象 - 只要您 return 可以定义从 GraphQLObject 的映射的独特对象就没关系类型(第二次回调需要)。