碎片不能在这里传播,因为“X”类型的对象永远不能是“Y”类型

时间:2017-06-06 21:20:25

标签: reactjs graphql relay

在这种情况下,键入“X”为Application,类型“Y”为“Node”类型 - 我可以看到为什么会发生这种情况,但我对Relay的理解不是'足以理解如何解决它。 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”不能在这里传播,因为“节点”类型的对象永远不能是“应用程序”类型 - 或者是那种效果。

我有点困惑,因为如果我要写一个原始查询并直接通过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和一些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),但这不起作用...不真的很确定从哪里去。

2 个答案:

答案 0 :(得分:1)

  • 您需要为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没有返回任何内容,则初始提取时不会出现错误。如果这没有意义,或者你仍在努力,你可以发布一个链接到回购,我会调查它。

答案 1 :(得分:1)

为了对此进行更新,我走的是正确的道路。

当前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
  }
)

我不确定这是否是最好的方法,但它似乎可以解决问题。要点是,如果我想要返回的节点类型是Application,我将返回GraphQL对象 - { ... name: "Application" ... }我们将在下一个中使用name字段step(nodeDefinitions中的第二个回调)只是重新返回Application。我认为你可以返回一个“自定义”对象或其他东西 - 只要你返回一些独特的东西就可以了,你可以定义一个映射到GraphQLObject类型(第二个回调需要)。< / p>