1

I just started to work with GraphQL and I am setting up a server with webonyx/graphql-php at the moment. Since a GraphQL query already has to contain the resulting data structure, I am not quite sure how to get dynamic data. Assumed that I query the content which consists different element types and my final structure should look like this:

{
    "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
            ]
        }
    }
}

How could I write a query for this example?

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

And how would a type definition for the content section look like? There is a defined set of element types (headline, image, review, many more) but their order and number of elements is unknown and they have only one field, type, in common. While writing the query in my frontend, I don't know anything about the content structure. And what would the graphql-php type definition for the content section look like? I couldn't find any similar example online, so I am not sure if it is even possible to use GraphQL for this use case. As an extra information, I always want to query the whole content section, not a single element or field, always everything.

1 Answer 1

1

When you're returning an array of Object types, but each individual item could be one of any number of different Object types, you can use either an Interface or a Union. We can use an Interface here since all the implementing types share a field (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
    }
]);

Types that implement the Interface need to do so explicitly in their definition:

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

Now if you change the type of the content field to a List of content, you can query only fields specific to each implementing type by using 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
    }
  }
}

Please see the docs for more details.

Sign up to request clarification or add additional context in comments.

4 Comments

But since i don't know which content types are present i have to add them all in the query, every time, right? Lets say I have 50 different types, the dataset i want to query has only one headline (what my frontend doesn't know), then I still have to write down all possible types and their fields. Is there a way to shorten that? I already read that there is no * operator, so any other ways?
No, you have to explicitly define each type and then explicitly request each type when making the query. On the one hand, that's a pain. On the other hand, it lets you specifically request which fields you want on a per-type basis. If you have more than one query that requests the Content type, you can use a fragments to reduce redundancy.
If you're really opposed to writing all that out, you could foreseeably use an introspection query to figure out all the implementing types and their fields and then use that to construct your query.
Not the answer i wanted to hear, but thats the concept how it works, I already thought that it will be like this. Thanks for your help and the helpful example!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.