DEV Community

Lukie Kang
Lukie Kang

Posted on

Figuring Out Gatsby #5 - GraphQL - How Gatsby eats data

In my last post I actually didn't talk much about Gatsby and instead set up a Sanity backend for Gatsby to ingest somehow.

The gist of the Sanity backend is that we have the following data for our restaurant app to use:

  • dishes, our meals
  • intolerances, things like gluten that can be in dishes
  • employees, who work at the restaurant
  • jobs, the jobs at the restaurant which an employee has

Regardless of how that data exists we need a way to show it for visitors to our Gatsby site so that's what we will talk about in this post. There are a few steps to get there:

  1. Setting up Gatsby config to use plugins
  2. Connect Gatsby to Sanity using the API securely 3.

Set up Gatsby Config

gatsbyconfig.js which may need creating on your root folder, and sets up things that apply across your site. The most common things to set up are:

  1. Site Metadata - Basic properties of your site
  2. Plugins - Extra stuff out there to be used.
  3. Flags - To allow experimental/non-standard features
  4. Prefix - To set up Gatsby in a particular location on the domain, i.e. for blogs
module.exports = {
  siteMetadata: {
    title: `The Cat and Bear Restaurant`
    siteUrl: `whatever.com`
    description: 'Purrfect Food. Roarsome ambiance'
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we actually have some data we can head to localhost:8000/___graphql to build our first query:

query MyQuery {
  site {
    siteMetadata {
      title
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Should return:

{
  "data": {
    "site": {
      "siteMetadata": {
        "title": "The Cat and Bear Restaurant"
      }
    }
  },
  "extensions": {}
}
Enter fullscreen mode Exit fullscreen mode

Hol' Up, what's this GraphQL stuff?

If you haven't seen graphql before then it. Put simply graphQL can let make queries (reading data) and mutations (changing data) using the syntax that is a little bit like working with JSON (...not really true but best I can do in a sentence.) Its more fun than writing an SQL query at least.

It will be quite the detour to explain it fully but I can recommend the video series by The Net Ninja to get the general gist of it. Watch the first few videos at least, I find the visualisations help a lot in making sense of how it works.

GraphQL is the backbone of how Gatsby handles data so it's important to get it understood.

Pluggin' In to Gatsby Plugins

Plugins are a superpower of Gatsby, taking what already exists and hooking it up in your own app. At the time of writing there are 2516 plugs available. You can view the Gatsby Plugin Library to get a flavour of what things are available.

Adding a plugin is as easy as specifying the name of the plugin:

module.exports = {
  siteMetadata: {
    title: `The Cat and Bear Restaurant`
    siteUrl: `whatever.com`
    description: 'Purrfect Food. Roarsome ambiance'
  },
  plugins: [
    'PLUGIN_NAME'
  ]
}
Enter fullscreen mode Exit fullscreen mode

This gets it working in the most default manner possible but the documents usually have options we can configure. For the site map plugin we can do something like this:

plugins: [
  //assume other plugins exist in this array
  {
    resolve: `gatsby-plugin-sitemap`,
    options: {
      sitemapSize: 5000
    }
  }
]
Enter fullscreen mode Exit fullscreen mode

Important Note: It won't do much till you also npm install the relevant plug in by its name.

Getting plugins in Gatsby is a doddle, any complexity will come from the Plugin itself so it will require studying the docs for each one. In my case, we have to get Gatsby talking to Sanity so let's take a deeper look at that:

  1. Deploy graphQL for Sanity. In your Sanity folder type sanity graphql deploy <dataset_name>

  2. Back in the Gatsby folder, get it installed with npm install gatsby-source-sanity

  3. Get some details of your Sanity Project. Assuming you have set up a project at (https://manage.sanity.io/projects/) we will need:

  • Project ID
  • The name of the dataset
  • Token. This is a bit more involved. We can create a token by going to 'settings', 'api' and 'add new token'. Give it a label for your own info and copy the long string that appears somewhere. While you are in the API settings, take a mental note that we should specify CORS origins for the URL that will allow us talk to Sanity when it is in production.
plugins: [
    {
      resolve: `gatsby-source-sanity`,
      options: {
        projectId: `<YOUR SANITY PROJECT ID`,
        dataset: `<PRODUCTION IN MY CASE>`,
        watchMode: true, //Allows changes to be reflected in Realtime for development
        token: process.env.SANITY_TOKEN, //DO NOT put you token in here. We need to keep our token secret. So we stick it into a .env file. See below...

      },
    },
  }
]
Enter fullscreen mode Exit fullscreen mode

ENV files, to stop ENVious hackers.

Quick aside, API tokens are sensitive, if people have access to them, they can do bad things. Our gatsby-config will be included in version control such as GitHub so we can put the token there. Instead, we just place a reference to an env file that contains secrets and doesn't go into version control. As an aside to our aside, having environment variables is also handly for things that do change between environments, such as connecting to a test database as opposed to a production one, without changing the

  1. npm install dotenv which allows us to use environment files easily
  2. Create a .env in the root of our gatsby site.
  3. Specify what SANITY_TOKEN is:

SANITY_TOKEN=reg4ergGW...etc

  1. Lastly we need to configure dotenv in our gatsby config file:
import dotenv from 'dotenv'
dotenv.config({path: '.env'})
Enter fullscreen mode Exit fullscreen mode

This will get the config file using our API Key securely.

Lastly, we should test it all works, a quick way is to console log the variable (if local) in gatsby-config to see if it is working properly. But if it is all hooked up as intended, when we go to our GraphiQL we should start seeing the contents of our Sanity popping in. Sanity data should start with allSanity so that:

query MyQuery { 
  allSanityMeals {
    nodes {
      name
    }
  }
  }
Enter fullscreen mode Exit fullscreen mode

Should return all the names of our meals in our hypothetical restaurant site. Phew, the above looks fairly tricky if you have never done something like this before but compared to hooking up a separate backend, I promise, it's a relative breeze!

3. Getting it visible via Gatsby Queries

So far we have gotten Gatsby to talk to our Sanity via GraphQL. The last step is getting the data from GraphQL onto our pages. Pretty much the whole reason for two wholly unrelated blog posts. As before all my examples revolve around a hypothetical restaurant site that cares about showing off what it has on its menu.

In Gatsby, at present, there can are two types of queries we can write to get data into our components and onto the page

  1. Page Queries. These allow variables but only can be run on a top-level page
  2. Static Query - Do not allow for variables, but can exist everywhere

Images are a special bit of data we can look at in more detail.

Page Queries

Page queries are pretty straightforward. Here is how we might get the dishes from the database by adding the following GraphQL query to the Food page where we might see all the dishes:

import React from 'react';

function FoodPage() {
  return (
    <div>
      <p>This is the Food page, where the dishes we serve are listed</p>
    </div>
  );
}

export const DishQuery = graphql`
  query DishQuery {
    dishes: allSanityDish {        //rename the output something nicer
      edges {
        node {
          id
          name
          price
          intolerences { 
            name
          }
          image {                // We will talk images in a bit
            asset {
              fluid(maxWidth: 400) {
                src
              }
            }
          }
        }
      }
    }
  }
`;

export default FoodPage;
Enter fullscreen mode Exit fullscreen mode

If that works, you can use React Dev tools to see that the dish data has appeared in props. A good step but let's see if we can manipulate it some more by accessing the props in our code.

In our FoodPage component we can access the data by passing in the props, or more exactly the data field within props. At this point we can use that data however we like in the component:

function FoodPage({ data }) {
  const dishes = data.dishes.edges;
  return (
    <div>
      <h1>We currently serve {dishes.length} dishes.</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

From there you can build extra components for mapping over the array if you so wish to pass dishes down as props. I won't get into that but if you have worked with React that should be fairly straightforward, here is the component file I ended up with:

import React from 'react';

function DishItem({ dish }) {
  return (
    <div>
      <h2>
        {dish.name} - {dish.price}{' '}
      </h2>
      <h3>Intolerence information:</h3>
      <p>
        {dish.intolerences.map((intolerence) => intolerence.name).join(', ')}{' '}
      </p>
    </div>
  );
}

export default function DishList({ dishes }) {
  return (
    <div>
      {dishes.map((dish) => (
        <DishItem key={dish.id} dish={dish.node} />
      ))}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

If you have never hooked up a separate backend to a frontend, the above might look a little scary but trust me, compared to most options, the configuration is a breeze. Though I use Sanity, most headless CMSes work on a similar basis bar some syntactical (is that a word?) differences.

When doing a full stuck app, setting up the conversation between front-end and back end is something I don't enjoy but by breaking it down into smaller steps, it is a bit less scary.

Discussion (0)