How we send data from Django to Gatsby.js through GraphQL (part two)

Maciej Baron
Good Praxis
Published in
3 min readAug 25, 2022

In our previous article, Igor explained how to configure Django to expose a GraphQL endpoint that can be consumed by an external piece of software. Now I’ll explain how to consume that data in Gatsby.js. I’ll assume you are familiar with using GraphQL to create pages.

The goal of this exercise is to create a custom, tailored CMS that can be used with Gatsby, which supports text and image content.

Gatsby.js offers several different plugins which allow you to source data from different headless backends, for example the popular gatsby-source-wordpress

However, you are not just limited to using established content management systems. You can use any backend which offers GraphQL — even one created by yourself — by installing gatsby-source-graphql and pointing it at your endpoint:

{
resolve: 'gatsby-source-graphql',
options: {
typeName: 'DJANGO',
fieldName: 'django',
url: 'https://ourwebsi.te/graphql',
},
},

If you followed the previous article, you can point to your local instance by setting the URL to http://localhost:8080/graphql

Keep in mind that if you are running both a local instance of your Django backend and Gatsby.js at the same time, you need to use different ports. Make sure you don’t get them mixed up!

Now after you restart your server, you can query data from your endpoint just like you would with everything else. You can easily view the data using Gatsby’s inbuilt GraphQL browser.

For instance, to create pages based on the data, you create your gatsby-node.js file and prepare an exportPages function. Here’s an example with some artwork data:

exports.createPages = async ({ actions, graphql }) => {
const { data } = await graphql(`
query {
django {
allArtworks {
slug
}
}
}
`);
const { django: { allArtworks } } = data;
allArtworks.forEach((edge) => {
const { slug } = edge;
actions.createPage({
path: `artwork/${slug}`,
component: require.resolve('./src/templates/artwork.tsx'),
context: { slug },
});
});

So far so good. This works well for text content, but what about images? By default, we just get the relative path to the image. That’s fine — we can use this to embed an image — but what if we want to do some image processing with gatsby-image-plugin?

Here’s where gatsby-filesystem-source and the createResolves API comes in handy. First, make sure you install the image plugin and its dependencies.

We then create a constant called IMAGE_PREFIX which will tell our resolver where do our media images reside (i.e. where do they go when uploaded in Django). After that, we can write our createResolvers function in our gatsy-node.js file:

const { createRemoteFileNode } = require('gatsby-source-filesystem');const IMAGE_PREFIX = 'https://ourwebsi.te/media/';exports.createResolvers = async (
{
actions,
cache,
createNodeId,
createResolvers,
store,
reporter,
},
) => {
const { createNode } = actions;
await createResolvers({
DJANGO_ArtworkType: {
imageFile: {
type: 'File',
async resolve(source) {
const { image } = source;
return createRemoteFileNode({
url: encodeURI(IMAGE_PREFIX + image),
store,
cache,
createNode,
createNodeId,
reporter,
});
},
}
}
});
};

What happens here is we create a new field called imageFile which will resolve to a remote file node. The resolve()function will be called with source which is our original objects. We grab image from it, which is the path to the uploaded file, set the type to 'File' and call the createRemoteFileNode with the correct URL.

So why do we have to do this in the first place? Well, in our previous article we created a field called image :

image = models.ImageField(upload_to=’images/’, blank=True, null=True)

This is exposed correctly through GraphQL, but only as a string. Our resolver turns it into a file node, which we can then use in our code. For instance, we can now create thumbnails or resized version of our image, just like we would with any other image node:

imageFile {
childImageSharp {
gatsbyImageData(
width: 600
placeholder: BLURRED
quality: 95
)
}
}
...import { GatsbyImage, getImage } from 'gatsby-plugin-image';...<GatsbyImage image={getImage(imageFile)} />

We now have a fully customised Django backend with image support that works with our Gatsby.js build. Combine the robustness and flexibility of Django with the speed and efficiency of Gatsby.js!

--

--