1 t6mJbJcg5NoFC1VotSyKEw

In some cases, an API could return an array containing multiple different values. In our case, we use Contentful for all our content related pages where we can have multiple different unrelated content models to build up a page. From a Contentful way of working this works fine, but when connecting to GraphQL we ran into some questions. How will you define your query, schemas, type definitions and keep it all structured?

Using fragments in the query

Our first approach was adding all the possible properties to the items query wherein the end we got a list of all possible properties and no clue which property belongs to which content model.

// just a small part of the properties in our items array  
items {  
  filters  
  id  
  imageUrl  
  link  
  name  
  overlayUrl  
  productNumbers  
  recommenderType  
  subtitle  
  title  
  type  
}

The more structured way is to split up the query to match the models which we defined in Contentful so we created afragment matching every model.

fragment RecommenderFragment on Recommender {  
  id  
  recommenderType  
  type  
}fragment TileFragment on Tile {  
  id  
  imageLink  
  imageUrl  
  subtitle  
  title  
  type  
}fragment ProductNumbersFragment on ProductNumbers {  
  id  
  productNumbers  
  filters  
  type  
}

It’s a little bit more boiler plating, but it gives a better view of your data. You could even create a basic fragment for recurring properties like id and type.

Using unions in the type definitions

So we split up our query with fragments, but how to structurize the type definitions? How can you explain that the items can be either one of Recommender, Tile, or ProductNumbers? The answer here is to use the union statement. You can create your type definitions like you usually would do and only add the union statement to declare of which types it can be.

union Item = Recommender | Tile | ProductNumberstype Content {  
  items: \[Item\]  
}type Recommender {  
  id: ID!  
  recommenderType: String  
  type: String!  
}type Tile {  
  id: ID!  
  imageUrl: String  
  imageUrl: String  
  subtitle: String  
  title: String  
  type: String!  
}type ProductNumbers {  
  id: ID!  
  productNumbers: \[String\]  
  filters: \[String\]  
  type: String!  
}

Resolving the correct type

After we split up the query and type definitions it’s time to tell the resolver to which type it should resolve the data. We based our resolving on the type we send with each item in our data where it matches our types in the type definitions exactly. You could also do some manual matching here based on other properties in your data.

Item: {  
  \_\_resolveType: obj => obj.type,  
},

Combining queries with unions

Then the final step is updating the query we started with to work with both the created fragments and union statement.

items {  
  // defines the union  
  ... on Recommender {   
    // spread in the fragment  
    ...RecommenderFragment   
  }  
  ... on Tile {  
     ...TileFragment  
  }  
  ... on ProductNumbers {  
     ...ProductNumbersFragment  
  }  
}

It’s a little bit more work and some more coding in the end, but in return, you’ll get a nicely structured setup of your data.

Related posts