<p><span class="drop-cap">H</span>ere's a cheat sheet to show you a couple of examples of <strong>GraphQL</strong> queries using version <strong>8.x-3.x</strong> of <a href="https://www.drupal.org/project/graphql">Drupal's GraphQL module</a>. This list is not intended to be exhaustive, it's just a sample of common queries that I've used in almost all decoupled sites that I've worked on.</p>
<p>Enough talking, show me the code! ?</p>
<h2>Get a single node by its nid</h2>
<p>Suppose that we have a node with id <code>1</code>. To query the basic information about that node, we can use the query below.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
entityId
title
status
}
} </code></pre>
<p>Only fields that belong to all entities and nodes can be fetched using this query. Keep in mind that <strong>entityId</strong> belongs to all entities (a node is an entity), and <strong>title</strong> and <strong>status</strong> are fields of all nodes, regardless of their bundle.</p>
<h2>Get a single node of a specific content type by its nid</h2>
<p>If we want to retrieve fields that belong only to a specific content type we have to use the fragment associated with that content type. For example, suppose that we have the <strong>Article</strong> content type, and it has the <strong>field_kicker</strong> field, so in order to get the value of the <strong>field_kicker</strong>, wrap the <strong>fieldKicker</strong> field inside the <strong>NodeArticle</strong> fragment.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
entityId
title
status
... on NodeArticle {
fieldKicker
}
}
}</code></pre>
<p>Remember that fields and properties are in <em>camelCase</em>, so <strong>field_kicker</strong> becomes <strong>fieldKicker</strong>. On the other hand, the nodes' fragments name has the form <em>Node</em> + <em>Content Type name</em>, so the fragment for the content type <strong>Article</strong> is <strong>NodeArticle</strong>.</p>
<h2>Querying a list of nodes</h2>
<p>Imagine that our content type <strong>Article</strong> has the field <strong>field_section</strong> that indicates the section the article belongs to. For the sake of simplicity, suppose that sections are stored as strings. So, to get the 10 latest articles of <em>Sports</em> section, we can use the next query.</p>
<pre>
<code class="language-json">query myQuery {
nodeQuery(
filter: {
conditions: [
{ field: "type", value: "article" },
{ field: "status", value: "1" },
{ field: "field_section", value: "sports" },
]
},
sort: { field: "created", direction: DESC },
limit: 10,
) {
entities {
entityId
entityLabel
}
}
}</code></pre>
<p>If you want to filter by an entity reference, use the referenced entity id in the "<em>value</em>" field.</p>
<h2>Querying taxonomy terms</h2>
<p>To get a taxonomy terms list of a specific vocabulary, for example, the "<em>tags</em>" vocabulary, use a query like the one below.</p>
<pre>
<code class="language-json">query myQuery {
taxonomyTermQuery(
filter: {
conditions: [
{ field: "vid", value: "tags" },
{ field: "status", value: "1" },
],
},
) {
entities {
entityId
entityLabel
}
}
}</code></pre>
<h2>Using aliases</h2>
<p>We can rename the result of a field to anything we want.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
id: entityId
title
... on NodeArticle {
section: fieldSection
}
}
}</code></pre>
<p>And we'll get the result</p>
<pre>
<code class="language-json">{
"data": {
"nodeById": {
"id": "1",
"title": "My awesome article!",
"section": "sports"
}
}
}</code></pre>
<p>Sometimes is necessary to use aliases, for example when we want to make the same query in a single request.</p>
<pre>
<code class="language-json">query myQuery {
tags: taxonomyTermQuery(
filter: { conditions: [{ field: "vid", value: "tags" }] },
) {
entities {
entityLabel
}
}
topics: taxonomyTermQuery(
filter: { conditions: [{ field: "vid", value: "topics" }] },
) {
entities {
entityLabel
}
}
}</code></pre>
<p>In the example above we are querying <em>tags</em> and <em>topics</em> using <strong>taxonomyTermQuery</strong> in both cases, so in order to differentiate the results, we are forced to use aliases.</p>
<h2>Using fragments</h2>
<p>There are times when we want to reuse the same query in many places. For example, suppose that our articles have a field <strong>field_tags</strong> that reference taxonomy terms of vocabulary <strong>Tags</strong>, and in another part of our site we show a list of those tags in the same way that we do in the articles, I mean, using the same fields. In these kinds of cases, fragments are useful to avoid code duplication.</p>
<pre>
<code class="language-json">query myQuery {
article: nodeById(id: "1") {
id: entityId
title
... on NodeArticle {
fieldTags {
entity {
...Tag
}
}
}
}
tags: taxonomyTermQuery(
filter: { conditions: [{ field: "vid", value: "tags" }] },
) {
entities {
...Tag
}
}
}
fragment Tag on TaxonomyTermTags {
id: entityId
name: entityLabel
}</code></pre>
<h2>Querying referenced paragraphs</h2>
<p>A very common use case for paragraphs is when a content type has a field that can reference multiple types of paragraphs. For example, the content type <strong>Page</strong> can have a <strong>field_sections</strong> field that references paragraphs of type <strong>tag_section</strong> for showing the latest tags, and a paragraph of type <strong>articles_section</strong> for the latest articles. We are not limited to show only one type of paragraph per field, to query all the values for the <strong>field_section</strong> we just need to list the supported fragments for that field. It'll be clear with an example.</p>
<pre>
<code class="language-json">query myQuery {
page: nodeById(id: "2") {
title
... on NodePage {
fieldSections {
entity {
...TagSection
...ArticlesSection
}
}
}
}
}
fragment TagSection on ParagraphTagSection {
# The required fields
}
fragment ArticlesSection on ParagraphTagSection {
# The required fields
}</code></pre>
<p>The use of fragments in the query above is not necessary but makes the code more readable. Note that even though the first listed fragment is the <strong>TagSection</strong>, this doesn't mean that the section to appear first will be the <strong>TagSection</strong>, the order saved in the CMS is preserved.</p>
<h2>Querying image with Image Styles</h2>
<p>Suppose that we have an image style <strong>square_max_800_px</strong> as machine name, in <strong>GraphQL</strong> the image style name is transformed to <strong>SQUAREMAX800PX</strong>. Note how the underscores are dropped and the image style's machine name is capitalized.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
title
fieldImage {
url
alt
title
squareStyle: derivative(style: SQUAREMAX800PX) {
url
width
height
}
}
}
}</code></pre>
<p>We can fetch more than one image style per single query using aliases.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
title
fieldImage {
url
alt
title
squareStyle: derivative(style: SQUAREMAX800PX) {
url
width
height
}
wideStyle: derivative(style: WIDEMAX800PX) {
url
width
height
}
}
}
}</code></pre>
<h2>Format dates</h2>
<p><strong>GraphQL</strong> supports some data transformations out of the box, for example, to format dates.</p>
<pre>
<code class="language-json">query myQuery {
nodeById(id: "1") {
title
created: entityCreated(format: "d/m/yy")
}
}</code></pre>
<p>The <a href="https://www.php.net/manual/es/function.date">available formats</a> are those supported by the date function in PHP.</p>
<p> </p>