GraphQL 模式拼接选择集中是否禁止具有列表类型的字段?

问题描述

我有一个看起来像这样的实体数组:

const aEntities = [
    {
        id: 1,name: 'Test',onetoManyRelation: [
            {
                id: 2
            },{
                id: 3
            }
        ],onetoOneRelation: {
            id: 1
        }
    }
];

实体由类型 AType 表示。我想在单独的子模式中扩展这种类型,并证明可以添加分别从 onetoOneRelationonetoManyRelation内容派生其值的字段。

以下架构实现了基于 onetoOneRelation 的派生字段,工作正常:

const aSchema = makeExecutableSchema({
    resolvers: {
        Query: {
            aEntities: () => aEntities
        }
    },schemaTransforms: [stitchingDirectivesValidator],typeDefs: gql`
        ${allStitchingDirectivesTypeDefs}

        type AType {
            id: ID!
            name: String!
            onetoOneRelation: AEmbeddedType!
        }

        type AEmbeddedType {
            id: ID!
        }

        type Query {
            aEntities: [AType!]!
        }
    `
});

const bSchema = makeExecutableSchema({
    resolvers: {
        AType: {
            onetoOneId: ({ onetoOneRelation }) => onetoOneRelation.id
        },Query: {
            aEntities_fromBSchema: (_,{ keys }) => keys,}
    },typeDefs: gql`
        ${allStitchingDirectivesTypeDefs}

        type AType @key(selectionSet: "{ onetoOneRelation { id } }") {
            onetoOneId: String!
        }

        scalar Key

        type Query {
            aEntities_fromBSchema(keys: [Key!]!): [AType!]! @merge
        }
    `
})

const schema = stitchSchemas({
    subschemaConfigTransforms: [stitchingDirectivesTransformer],subschemas: [
        {
            schema: aSchema
        },{
            schema: bSchema,}
    ]
})

但是一旦我将 onetoManyRelation { id } 添加到 selectionSet 我遇到了问题:

const aSchema = makeExecutableSchema({
    resolvers: {
        Query: {
            aEntities: () => aEntities
        }
    },typeDefs: gql`
        ${allStitchingDirectivesTypeDefs}

        type AType {
            id: ID!
            name: String!
            onetoManyRelation: [AEmbeddedType!]!
            onetoOneRelation: AEmbeddedType!
        }

        type AEmbeddedType {
            id: ID!
        }

        type Query {
            aEntities: [AType!]!
        }
    `
});

const bSchema = makeExecutableSchema({
    resolvers: {
        AType: {
            onetoManyIds: ({ onetoManyRelation }) => onetoManyRelation.map(({ id }) => id),onetoOneId: ({ onetoOneRelation }) => onetoOneRelation.id
        },typeDefs: gql`
        ${allStitchingDirectivesTypeDefs}

        type AType @key(selectionSet: "{ onetoOneRelation { id },onetoManyRelation { id } }") {
            onetoOneId: String!
            onetoManyIds: [String!]!
        }

        scalar Key

        type Query {
            aEntities_fromBSchema(keys: [Key!]!): [AType!]! @merge
        }
    `
})

我收到以下错误

onetoManyRelation.map is not a function

当我在 aEntities_fromBSchema 解析器中记录 keys 参数时,似乎 onetoManyRelation 根本没有被解析为一个数组,而是一个(空)对象:

[
  {
    onetoOneRelation: [Object: null prototype] { id: '1' },onetoManyRelation: [Object: null prototype] { id: undefined },__typename: 'AType'
  }
]

graphql-tools v 7.0.2 开始,是否完全禁止在键选择集中引用列表类型?看起来我实际上可以通过使用在 SDL 之外定义的子模式合并配置来规避这个问题(没有批处理,而是使用 argsselectionSet 配置参数),但出于验证/网关的原因,我d 更喜欢让我的所有子模式都包含它们所有的类型合并指令作为 SDL 指令。

铌。这是现实世界问题的简化表示。

铌2。在现实世界的应用程序中,我的子模式之一是我无法控制的远程 GraphQL 应用程序,因此需要在拼接层进行一些高级定制。

编辑:只需将以下内容添加到子模式配置的合并选项中似乎就可以解决问题。有人知道为什么这似乎不能用 SDL 指令重现的一个很好的理由吗? (或者这样做的好方法?)

// AType
{
  argsFromKeys: (keys) => ({ keys }),fieldName: 'aEntities_fromBSchema',key: ({ onetoOneRelation,onetoManyRelation }) => ({ onetoManyRelation,onetoOneRelation }),selectionSet: '{ onetoOneRelation { id },onetoManyRelation { id } }'
}

解决方法

您可能发现了一个错误!请在 GitHub 存储库上打开一个问题,以便我们可以跟踪它。 :)