GraphQL for Drupalers - part 4 - fetching the entities
GraphQL is becoming more and more popular every day. Now that we have a beta release of the GraphQL module (mainly sponsored and developed by Amazee Labs) it's easy to turn Drupal into a first-class GraphQL server. In this series, we'll try to provide an overview of its features and see how they translate to Drupal.
In the last post we talked about the basic building blocks of every GraphQL query - the fields. We've discussed their types and traits as well as described the rules according to which Drupal fields turn into GraphQL fields. This week we were going to expand the topic further and cover field creation, but Daniel Noyola asked an interesting question in the comment below one of the recent articles:
How can I filter the results in a nodeQuery? Like I would in a normal View or with the "where" clause in a SQL Statement. I noticed that it receives a NodeQueryFilterInput but I don't see how to use it.
Fetching entities based on a filter or a set of filters is a common use case, so let's focus on that first.
There are two ways to query the entity repository. First one would be through the entityQuery fields which are shipped with the core module but are limited in functionality. They only allow us to filter by base fields and there's no way to use an operator other than equals to. The other approach is much more powerful, as it's based on Views. It requires an additional module - graphql_views - to be installed though. Let's start with the built-in way.
Each entity type in the system gets its own query field. Let's see in the explorer how it looks like for nodes:
So it's a field (blue) with 3 arguments: offset, limit and filter (purple) which returns a value of type EntityQueryResult (all types are in yellow).
The first two arguments, offset and limit, are for paging and they work the same way as in SQL. Both are integers and both have default values of 0 and 10 respectively (green). Arguments that have default values can be omitted. We'll use this feature in a while.
The last argument - filter - is of a complex type NodeQueryFilterInput. Let's click it:
So it comprises all the base fields of the entity type that is being queried. It's not enough to issue arbitrary queries but it will suffice for a simple use case. This is how we could fetch a list of articles created by a given user:
We haven't specified the offset nor the limit, so they'll get their default values. It means that the output will contain at most 10 results, starting from the result number 0.
That's cool, but what if we wanted to order the articles by node id (nid) to only show the latest articles? Or filter by tags? Or fetch the title text of an image that is attached to a media entity that is connected with the first event that starts after the article's release date?
Use The Views
The answer is: we can do it like we'd normally do it in Drupal - with a view. Views integration has been moved to a separate project, so it has to be downloaded with composer (composer require drupal/graphql_views), from drupal.org or from github.
With graphql_views enabled we can add a GraphQL display to any view in the system.
Now we can sort the results, filter based on content fields and add relationships. We also have the option to return either the full entities, just a selection of fields, or even search results taken straight from a search server.
Contextual filters set in the view will automatically turn into the arguments of the GraphQL field. Let's see an example:
This field represents a simple view showing nodes. It has one contextual filter - Content: Authored by - so the corresponding input type consists of just one field:
and its row type is set to Entity (as pictured on the screenshot above), so the result will be of type NodeArticle:
We can use the filed like this:
Views integration is a pretty broad topic, so in the next post we might try to cover it in more detail. There are quite a few more interesting aspects like sorting, exposed filters, and attaching views to entities, so we'll focus on that in an attempt to fully answer Daniel's question. For those interested in the back-end side of things I'd recommend the great Extending GraphQL series by Philipp Melab. The first post that explains how to create fields is here: Extending GraphQL: Part 1 - Fields.
P.S. GraphQL Views is not stable yet. In fact, two issues were spotted and fixed in the process of writing this article. If you spot a bug please report it on github or let us know in the #graphql channel at Drupal slack.