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:
- Setting up Gatsby config to use plugins
- 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:
- Site Metadata - Basic properties of your site
- Plugins - Extra stuff out there to be used.
- Flags - To allow experimental/non-standard features
- 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'
}
}
Now we actually have some data we can head to localhost:8000/___graphql
to build our first query:
query MyQuery {
site {
siteMetadata {
title
}
}
}
Should return:
{
"data": {
"site": {
"siteMetadata": {
"title": "The Cat and Bear Restaurant"
}
}
},
"extensions": {}
}
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'
]
}
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
}
}
]
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:
Deploy graphQL for Sanity. In your Sanity folder type
sanity graphql deploy <dataset_name>
Back in the Gatsby folder, get it installed with
npm install gatsby-source-sanity
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...
},
},
}
]
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
- npm install
dotenv
which allows us to use environment files easily - Create a
.env
in the root of our gatsby site. - Specify what SANITY_TOKEN is:
SANITY_TOKEN=reg4ergGW...etc
- Lastly we need to configure dotenv in our gatsby config file:
import dotenv from 'dotenv'
dotenv.config({path: '.env'})
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
}
}
}
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
- Page Queries. These allow variables but only can be run on a top-level page
- 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;
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>
);
}
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>
);
}
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.
Top comments (0)