Drupal Redirects in Gatsby.JS

Professional Article
June 13, 2021

If you’re running Drupal  + Gatsby.JS website, you’ll inevitably change the URLs of some of these articles (i.e. by changing the title) → and this will change the slug (URL) →and this will cause 404s (i.e. break all Social Media posts, etc). There’s a way to fix it.

The Reason

This depends on the case, in my case (and many other examples I’ve seen) - the slugs are generated by using Drupal's path aliases. And Drupal’s paths depend (usually) on the node’s title.

This has unforeseen consequences, once you change the title, the path is changed too and on the next build, Gatsby will stop recognizing the old paths, resulting in 404s. This happened to me - when I wanted to rename the initial article as “Part 1” (because I’ve written a “Part 2” later),  all my social-media posts were broken and Google also freaked out.

An easy way out would be to have the Gatsby paths depend on node IDs, but that would result in ugly URLs and we don’t want that, do we?

However, Drupal handles these path changes, by creating nice redirects, and it keeps track of all of the path changes ever. If you make 10 changes, there will be 10 redirects pointing to the same Node, and eventually redirecting to the currently used path alias.

The only left bit is to tell Gatsby about these redirects and teach it how to use those.

How to fix - Integrate routing with Drupal Redirects

Okay, first thing’s first - as of today (June 2021) - there’s this patch needs to be applied to redirect - https://www.drupal.org/node/3057679 - Patch #12. If you’re using the composer, just add these lines under “patches”:

  1. "drupal/redirect": {
  2.     "Redirect permissions": "https://www.drupal.org/files/issues/2019-11-12/3057679-12.patch"
  3. }

This patch basically allows anonymous users to ‘view’ redirects entities. This bit is important, because our Gatsby Drupal Source plugin queries as an anonymous user - and we want those Redirect entities to show-up in Gatsby's GraphQL. Make sure you check the permissions page and tick the ‘View indvidual URL redirections’ for anonymous users (after you apply the patch and clear the cache).

Now let’s fix the Gatsby part. For this, we need to edit gatsby-node.js:

  1. First - we want to get the createRedirect from the actions.
  2. Then, we want to query the Drupal redirects from the GraphQL - I switched everything to async + await because that’s how it was done in the original example that I followed.
  3. I aggregate ALL redirects for a given Drupal Node (source_uri) - because I assume we will make many changes to a given URL - this way we will end-up with multiple aliases per given Node.
  4. We return everything into the ‘redirects’ variable.
  1. exports.createPages = async ({ graphql, actions }) => {
  2.   const { createPage, createRedirect } = actions
  4.   const redirects = await graphql(`
  5.     {
  6.       allRedirectRedirect {
  7.         edges {
  8.           node {
  9.             redirect_source {
  10.               path
  11.             }
  12.             redirect_redirect {
  13.               uri
  14.             }
  15.           }
  16.         }
  17.       }
  18.     }
  19.   `).then(result => {
  20.     const data = [];
  21.     if (!result.errors) {
  22.       result.data.allRedirectRedirect.edges.forEach(({ node }) => {
  23.         const source_uri = node.redirect_redirect.uri.replace(/^entity:|internal:\//, '/')
  24.         if (!(source_uri in data)) {
  25.           data[source_uri] = [];
  26.         }
  27.         data[source_uri].push(node);
  28.       })
  29.     }
  30.     return data;
  31.   });
  33.   // ... continue here.
  34. }

Okay, so now we have all the redirects placed nicely in the variable, what next? Well, this part depends on your specific setup. In my case, a bit lower in the same createPages function, right after I create the needed blog pages (actually - right before), I do the following:  

  1.   result.data.allNodeArticle.edges.forEach(({ node }) => {
  2.      // … more code here… 
  4.      if (redirects[`/node/${node.drupal_internal__nid}`]) {
  5.         redirects[`/node/${node.drupal_internal__nid}`].forEach(redirect => {
  6.           createRedirect({
  7.             fromPath: redirect.redirect_source.path,
  8.             toPath: node.path.alias,
  9.             isPermanent: true,
  10.             status: 301
  11.           });
  12.         })
  13.       }
  15.      // … more code here… 
  16.   }

The actual inspiration / help that I got for this topic, came from Joe Shindelar’s twitter:

Joe’s tweet was exactly what I needed. But Joe’s image focuses on a single redirect case, while I expanded this to cover multiple aliases. 

For more posts related to Gatsby.JS + Drupal ? check-out the recommendations below the article. If you have any issues, suggestions or questions - reach out to me via the comment section below as well.


Feel free to ask any question / or share any suggestion!