在GraphQL中查询未知数据结构

时间:2019-01-25 13:15:07

标签: graphql graphql-php

我刚刚开始使用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。作为额外的信息,我始终希望查询整个内容部分,而不是单个元素或字段,而总是查询所有内容。

1 个答案:

答案 0 :(得分:0)

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

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