angle-downangle-leftangle-rightangle-upfacebookinstagramlinkedinTagtwitteryoutube-play
Skip to main content

An Experiment: GraphQL in Twig

Profile picture for user Calvin Tyndall
Calvin Tyndall Drupal Developer Follow
December 03, 2020

While experimenting with Gatsby + Drupal and doing research for my previous posts here, I came across the GraphQL Twig module.

This module is beta and hasn't had a lot of activity. I'm not sure how it addresses some deep Drupal theme issues, but it presents an interesting idea:

"The GraphQL Twig module allows you to inject data into Twig templates by simply adding a GraphQL query. No site building or pre-processing necessary."

It turns the data flow around from push to pull. The templates define what they want instead of trying to process a mass of data it may or may not need, that's been spawned and morphed through multiple layers of modules and processors. If this chunk of data doesn't have everything you want, you can avoid having to preprocess, or otherwise massage the data through the backend, thereby mitigating the already complex path that data takes to the browser.

I did a quick test to see if I could easily pull Paragraphs content into a node template from 2 references deep.

Example

Like my previous post, I have a content type with a Paragraph reference field. On that field I reference a "Columns" Paragraph. That Paragraph type also has a reference field that allows a "Text" Paragraph with "Heading" and "Text" fields.

I put the following query in the node.html.twig template:

Query


{#graphql
query($node: String!) {
  nodeById (
    id: $node
  ) {
    ... on NodeArticle {
      title
      column_wrapper: fieldComponents {
        entity {
          ... on ParagraphColumns {
            columns: fieldComponents {
              entity {
                ... on ParagraphText {
                  fieldHeading {
                    processed
                  }
                  fieldText {
                    processed
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
#}

It looks like a comment wrapped in {# #}, but that's how it works. Also notice I aliased the fieldComponents to help a bit with clarity in the result.

I could then dump the graphql variable to see this:

Result


array:1 [▼
  "nodeById" => array:2 [▼
    "title" => "Augue Erat Eros Nulla"
    "column_wrapper" => array:1 [▼
      0 => array:1 [▼
        "entity" => array:1 [▼
          "columns" => array:2 [▼
            0 => array:1 [▼
              "entity" => array:2 [▼
                "fieldHeading" => array:1 [▼
                  "processed" => "Heading 1"
                ]
                "fieldText" => array:1 [▼
                  "processed" => "<p>Text 1</p>"
                ]
              ]
            ]
            1 => array:1 [▼
              "entity" => array:2 [▼
                "fieldHeading" => array:1 [▼
                  "processed" => "Heading 2"
                ]
                "fieldText" => array:1 [▼
                  "processed" => "<p>Text 2</p>"
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  ]
]

This is a very easy way to access exactly the content we need in any given template. It's very much like we might use components in a decoupled JS front end, without all the additional cost and complexity. According to the limited documentation, we can inherit query fragments from templates we include, so we can build out atomic components that can be used to compose other components.

This seems like a promising alternative path at a time when a rigorous overhaul of the Drupal theme system is under way.

What I Couldn't Do

One thing I tried but could not do was to load a specific node revision using a variable. I tried the nodeRevisionById query but couldn't determine a way to pass the query the revision ID from the node. You'll notice in the nodeById query, I use $node as the variable when the argument is id. How this works is still a mystery to me but beyond the scope of this post to dig into. It says it will "automatically try to match template variables to query arguments".

Even if that's the case, I don't have direct access to the node vid in the template for it to match to. Even if I did, the argument for nodeRevisionById is id, not vid so that would conflict with nid. It's not clear. If I'm not able to load a specific node revision this way then I can't set up my node template to support content moderation.

Can I Go Further?

I found this example repo that uses GraphQL Twig to build a theme incorporating components from Storybook. It's a fantastic example except the only use of a variable I found was the same $node as above.

I hope to be able to explore this more and that this module gets a little more love and traction.

130 sites report using this module. Have you built a theme like this, or do you have more examples to share?

"Code like nobody is watching... but then refactor. ;)"

How Can We Help With
Your Next Project?