【问题标题】:Query unknown data structure in GraphQL在 GraphQL 中查询未知数据结构
【发布时间】:2019-06-19 08:03:00
【问题描述】:

我刚开始使用 GraphQL,目前正在使用 webonyx/graphql-php 设置服务器。由于 GraphQL 查询已经必须包含结果数据结构,我不太确定如何获取动态数据。假设我查询了包含不同元素类型的内容,我的最终结构应该如下所示:

{
    "data": {
        "dataset": {
            "uuid": "abc...",
            "insertDate": "2018-05-04T12:12:12Z",
            // other metadata
            "content": [
                {
                    "type": "headline",
                    "text": "I am a headline"
                },
                {
                    "type": "image",
                    "src": "http://...",
                    "alt": "I am an image"
                },
                {
                    "type": "review",
                    "rating": 3,
                    "comment": "I am a review"
                },
                {
                    "type": "headline",
                    "text": "I am another headline"
                }
                // other content elements
            ]
        }
    }
}

如何为这个示例编写查询?

{
    dataset {
        uuid
        insertDate
        content {
            ????
        }
    }
}

内容部分的类型定义是什么样的?有一组已定义的元素类型(标题、图片、评论等),但它们的顺序和元素数量是未知的,它们只有一个字段,类型,共同点。在我的前端编写查询时,我对内容结构一无所知。内容部分的 graphql-php 类型定义会是什么样子?我在网上找不到任何类似的例子,所以我不确定是否可以在这个用例中使用 GraphQL。作为额外的信息,我总是想查询整个内容部分,而不是单个元素或字段,总是要查询所有内容。

【问题讨论】:

    标签: graphql graphql-php


    【解决方案1】:

    当您返回一个 Object 类型的数组,但每个单独的项目可能是任意数量的不同 Object 类型之一时,您可以使用 Interface 或 Union。我们可以在这里使用接口,因为所有实现类型共享一个字段 (type)。

    use GraphQL\Type\Definition\InterfaceType;
    use GraphQL\Type\Definition\Type;
    
    $content = new InterfaceType([
        'name' => 'Content',
        'description' => 'Available content',
        'fields' => [
            'type' => [
                'type' => Type::nonNull(Type::string()),
                'description' => 'The type of content',
            ]
        ],
        'resolveType' => function ($value) {
            if ($value->type === 'headline') {
                return MyTypes::headline();            
            } elseif ($value->type === 'image') {
                return MyTypes::image();
            } # and so on
        }
    ]);
    

    实现接口的类型需要在其定义中明确地这样做:

    $headline = new ObjectType([
        # other properties 
        'interfaces' => [
            $content
        ]
    ]);
    

    现在,如果您将content 字段的类型更改为content 的列表,则可以使用inline fragments 仅查询特定于每个实现类型的字段:

    query GetDataset {
      dataset {
        uuid
        insertDate
        content {
          type # this field is shared, so it doesn't need an inline fragment
          ... on Headline {
            text
          }
          ... on Image {
            src
            alt
          }
          # and so on
        }
      }
    }
    

    详情请见the docs

    【讨论】:

    • 但由于我不知道存在哪些内容类型,我必须每次都将它们全部添加到查询中,对吗?假设我有 50 种不同的类型,我要查询的数据集只有一个标题(我的前端不知道),那么我仍然必须写下所有可能的类型及其字段。有没有办法缩短它?我已经读到没有 * 运算符,所以还有其他方法吗?
    • 不,您必须显式定义每种类型,然后在进行查询时显式请求每种类型。一方面,这是一种痛苦。另一方面,它允许您根据每种类型专门请求您想要的字段。如果您有多个查询请求Content 类型,则可以使用片段来减少冗余。
    • 如果你真的反对写出所有这些,你可以预见地使用自省查询来找出所有实现类型及其字段,然后用它来构造你的查询。
    • 不是我想听到的答案,但这就是它的工作原理,我已经认为它会是这样的。感谢您的帮助和有用的示例!
    猜你喜欢
    • 2020-02-16
    • 2020-03-09
    • 1970-01-01
    • 2020-02-05
    • 2020-01-28
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2019-11-14
    相关资源
    最近更新 更多