Rewriting A Static Website Using Gatsby and GraphQL - Part 1
Tags: gatsby, graphql, jsx, javascript
Published: 2019-02-21 16:41:36

---
title: Rewriting A Static Website Using Gatsby and GraphQL - Part 1
published: true
description: I decided to update my personal site away from Jekyll. In the process I learned about GatsbyJS, GraphQL and all of the errors! Check out this series for a granular walkthrough.
tags: gatsbyjs, graphql, JSX, javascript
canonical_url: https://tenmilesquare.com/rewriting-a-static-website-using-gatsby-and-graphql/
series: Rewriting A Static Website Using Gatsby and GraphQL
---

<b>Originally posted on <a rel="noreferrer noopener" aria-label="ten mile square site (opens in a new tab)" href="https://tenmilesquare.com/blog/" target="_blank">Ten Mile Square's blog.</a></b>

<p>My <a rel="noreferrer noopener" aria-label="personal website (opens in a new tab)" href="https://www.laurieontech.com" target="_blank">personal website</a> is implemented using Jekyll, which I liked, but it has an unfortunate initial load behavior that just does not look good or provide the user experience I want. So, I recently decided to reimplement the site, and learn <a rel="noreferrer noopener" aria-label="GraphQL (opens in a new tab)" href="https://graphql.org/" target="_blank">GraphQL</a> along the way.</p>

<p>At around the same time a friend recommended <a rel="noreferrer noopener" aria-label="GatsbyJS (opens in a new tab)" href="https://www.gatsbyjs.org/" target="_blank">GatsbyJS</a>. Since Gatsby is meant to work with GraphQL out of the box it was a perfect choice. The goal was that it would be easier to learn both technologies if I was working towards a final product I was already familiar with.</p>

<h3>NextGen Generation</h3>

<p>Jekyll generates a static site using a mixture of Markdown (or in my case, Yaml), Html/CSS and the Liquid templating engine. In my site, I use Liquid templating to create static pages that can loop through and display the content I’ve defined in my Yaml files. That content can be blog posts (like this one), details of speaking engagements, etc. I can also define a template for a section of a page, like the header, and use Yaml to define the content of that section for each page. All of this gets built using `Jekyll build` and deployed using Firebase, though that’s a topic for another post.</p>

<p>On the other hand, Gatsby is based on React, so it’s mostly Javascript. It seems like quite the departure, and there are some significant changes, but GraphQL and Gatsby plugins make the changes simpler. To start, Gatsby comes with some starter templates. I originally began with just the default `new Gatsby &lt;project-name&gt;`. However, when I discovered a pre-styled <a rel="noreferrer noopener" aria-label="HTML5UP (opens in a new tab)" href="https://html5up.net/" target="_blank">HTML5UP</a> starter package I made a version with that instead. For me, it was beneficial to see an existing pre-styled page and start to learn from those patterns. As a general rule, I like to start with something that works and iterate to the functionality or look and feel I want.</p>

<!-- wp:heading {"level":3} -->
<h3>Digging In</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Part of what makes Gatsby so feature rich is the ability to add plugins. While most frameworks allow for plugins/libraries, those that exist for Gatsby are specific to that framework and decently fine-grained. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>My first goal is to limit the changes I need to make to my site. Specifically, I want to keep the data defined as static yaml so that I don't have to reformat all of it. I can do that by adding a couple of plugins. The first is</p>
<!-- /wp:paragraph -->

```js
{    
  resolve: `gatsby-source-filesystem`,
  options: {  
      path: `./src/data/`,
  } 
}
```

<!-- wp:paragraph -->
<p>This allows my code to look at files within the <span class="code" style="background-color:white">`src/data` </span>directory.  Now, all I have to do is take my files from the  `<span class="code" style="background-color:white">_data` </span>folder in the Jekyll project and drop them into the <span class="code" style="background-color:white">`src/data` </span>folder in the Gatsby project. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>At this point I'm able to find the files themselves, but I can't dig into the content inside them. To do that, I need to add the plugin<span class="code" style="background-color:white"> `gatsby-transformer-yaml`</span>. With that, my GraphQL queries can look inside the content of any yaml file in my project to query for results. I should note here that a similar plugin exists for markdown files if you would prefer that syntax.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now that I can access the data, I need to create a query to pull the information I want from it. A typical GraphQL query looks something like this:</p>
<!-- /wp:paragraph -->

```graphql
type Query {
     me: User
}
```

<!-- wp:paragraph -->
<p>In my case, using the yaml plugin, the query I need looks like this: </p>
<!-- /wp:paragraph -->

```graphql
{
    allSpeakingYaml {
        edges {
            node {
                conference
                year
                url
                date
                location
                image
                talks {
                    title 
                    video
                }
            }
        }
    }
}
```

<!-- wp:paragraph -->
<p>In this case the query starts with <span class="code" style="background-color:white">`allSpeakingYaml`</span> to direct GraphQL to look for this data in the speaking.yaml file. If I wanted to query blog.yaml file, for example, I'd start the query with allBlogYaml. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Hooking It Up</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>One of the gotchas I discovered was the error <span class="code" style="background-color:white">`Unknown field allSpeakingYaml on type Query`</span>. I saw this error a number of different times and the type of code that triggered it always seemed to be different. It took me a bit to determine what it was trying to convey. What the error really boils down to is that GraphQL is unable to find a matching result. This can mean it couldn't find a file that matched the first line, as I stumbled across when I my file was speaking.yml, no .yaml file meant the search failed. It can also be triggered by finding the file but not the associated content structure the query asks for. I again stumbled upon the error when I had forgotten to change allSpeakingYaml to allBlogYaml but had already changed the structure and keywords of the data I was looking for. Yet another way to find this error is by leaving out the system-file plugin; without it, the folder that holds my data is not visible to GraphQL and it will throw the same error.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Since I'm now error free it's time to look at the response of the query. One of the great things about Gatsby is that it comes with a browser view to test your GraphQL queries against, similar to Postman. I can use this endpoint to test out my queries and examine the structure of the response. This is important because in order to use JSX in React and display data on the web, it needs to be referenced appropriately. I'll start with querying my blog posts since it's the simplest structure. This is the response:</p>
<!-- /wp:paragraph -->

```json
{ 
 "data": { 
     "allPostsYaml": { 
         "edges": [ 
           { 
             "node": { 
                 "title": "Optimistic UI vs Intuitive UX", 
                 "url": "https://tenmilesquare.com/optimistic-intuitive/" 
                }
           }, 
           { 
             "node": { 
                 "title": "Technology for the Non-Technical", 
                 "url": "https://tenmilesquare.com/for-the-non-technical/" 
                 } 
           }
        ] 
     } 
  }
}
```

<!-- wp:heading {"level":3} -->
<h3>Mapping Array Objects</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>I want to put all the titles of my posts and their url links on my blog post page. In previous projects in Angular I've temporarily referenced the entire messy object and had it render with brackets and all just to make sure everything was working. Interestingly, even if I wanted to, I can't do that here, JSX doesn’t allow it and gives the error <span class="code" style="background-color:white">`Objects are not valid as a React child`</span>. So that means I need to be referencing the individual string literals that are available within the response. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Looking at the response object above, the first thing to notice is that <span class="code" style="background-color:white">data</span> and <span class="code" style="background-color:white">allPostsYaml</span> are objects. However, within those objects are <span class="code" style="background-color:white">edges</span>, which refers to an array. That means JSX needs to use map. </p>
<!-- /wp:paragraph -->

```jsx
{data.allPostsYaml.edges.map(({ node }, index) => ({node.title}))}
```

<!-- wp:paragraph -->
<p>Within the map I can reference <span class="code" style="background-color:white">node.title</span>, as in the example above, or <span class="code" style="background-color:white">node.url</span>. That means my site will go through all of the entries in the array and display the blog post titles which is exactly what I want.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>But not all of my yaml files have such simple structures. This is part of the response to my speaking object query:</p>
<!-- /wp:paragraph -->

```json
{
 "data": { 
     "allSpeakingYaml": { 
         "edges": [ 
           {
             "node": { 
                "conference": "Indy Code",
                "url": "https://indycode.amegala.com/",              
                "date": "April 24-26, 2019",            
                "image": "headshot.jpg",
                "talks": [
                   {                
                      "title": "How to Talk Like an Engineer",
                      "video": null
                   }, 
                   { 
                      "title": "A Software Engineer's Guide to DevOps", 
                      "video": null
                    } 
                 ]     
             }         
         }    
     }
}
```

<!-- wp:paragraph -->
<p>At the top level the response looks the same as the one for blog posts. However, within the response, the key <span class="code" style="background-color:white">`talks`</span> has an array value. My initial instinct was to add a map function inside the other map function and be done with it. Something like this: </p>
<!-- /wp:paragraph -->

```jsx
{data.allSpeakingYaml.edges.map(({ node }, index) =>
    ({node.talks.map(({ talk }) =>( {talk.title} )) 
))}
```

<!-- wp:paragraph -->
<p>But that didn’t work. It kept saying that talk wasn’t valid. Why? Well, I had to look very closely at the response object. In our previous example <span class="code" style="background-color:white">`edges`</span> is a key that references an array object, just like <span class="code" style="background-color:white">`talks`</span> is in this example. In both cases, within the arrays, there are objects that don't have a key reference. However, in the <span class="code" style="background-color:white">`edges`</span> example, those objects have another object inside, <span class="code" style="background-color:white">`node`</span>. So we're referencing an object and looking at its attributes. In the case of <span class="code" style="background-color:white">`talks`</span>, there are only keyed attributes, so we are able to reference them directly, like this:</p>
<!-- /wp:paragraph -->

```jsx
{data.allSpeakingYaml.edges.map(({ node }, index) =>
    ({node.talks.map(({ title, video }) => ( {title} )) 
))}
```

<!-- wp:paragraph -->
<p>I'll admit that I still expected to assign a reference key to each object in <span class="code" style="background-color:white">`talks`</span> and access the <span class="code" style="background-color:white">`title`</span> and <span class="code" style="background-color:white">`video`</span> data as attributes. However, we didn't do that to the <span class="code" style="background-color:white">`edges`</span> array, we went straight to referencing <span class="code" style="background-color:white">`node`</span>. So this is the same. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>More To Come</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>At this point I have moved over my site data and made it accessible and viewable on the site's pages. That’s a good first step, but there is still lots to do. In my next post I’ll discuss removing some of the liquid templating instructions left over from my Jekyll implementation.</p>
<!-- /wp:paragraph -->