How to create a Gatsby Source Plugin

Author: David Fekke

Published: 5/28/2021

One of the powerful things about Gatsby is the way you can pull multiple sources of content from completely different areas into your site. Gatsby does this through plugins.

There are two primary forms of plugins for Gatsby, ‘source’ and ‘transformer’. Source plugins allow you to bring data from out side of your Gatsby site into Gatsby, and Transformer plugins allow you to massage and transform the data from your sources into the specific content you need in your site.

Once data is configured to be brought into your site through a source plugin, you will be able to use GraphQL queries to query the specific content you need added to your site.

You can also use Gatsby’s built in query editor that can be accessed via the GraphiQL http://localhost:8000/___graphql url after you run gatsby develop.

Sources

There are an unlimited number of sources for Gatsby that include APIs, content engines, static files and even databases. In this post I am going to create a plugin that pulls in content from an external API.

Creating the plugin

To create my Gatsby plugin, I am going to create a new Gatsby site and a Gatsby plugin module using the Gatsby CLI. Lets’ create the site first using the ‘Hello World’ starter.

gatsby new playground-site gatsby-starter-hello-world

Now lets’ create a source plugin in the same directory we created the playground site.

gatsby new source-plugin https://github.com/gatsbyjs/gatsby-starter-plugin

If you want to, you can also create the plugin into the ‘plugins’ folder in your playground-site folder. For this example we will keep the site and plugin in separate folders.

/playground-site
/source-plugin
├── .gitignore
├── gatsby-browser.js
├── gatsby-node.js
├── gatsby-ssr.js
├── index.js
├── package.json
└── README.md

Configuring your plugin

Now lets’ configure are ‘playground-site’ to use the plugin by editing the ‘gatsby-config.json’ file in the root of our ‘playground-site’ folder.

module.exports = {
  plugins: [require.resolve(`../source-plugin`)],
}

We can test that this is configured properly by run gatsby develop on our playground-site. You should see ‘Loaded gatsby-starter-plugin’ from the terminal when you go to run the playground-site.

Adding data to our Plugin

Now that we have our sample plugin, lets’ modify it so that it will pull in a source from an API. For this example I am going to use the Star Wars API. I want to be able to use GraphQL to query ship data from the Star Wars API.

Gatsby provides an API you can use to create GraphQL nodes through a function called createNode. We can use this inside of a function in the gatsby-node.js file that exports an async function called sourceNodes.

For this example I am going to get the data from the Star Wars API using the ‘axios’ module. In your plugin module you can add this with the following npm command;

source-plugin> npm i axios --save

This will add ‘axios’ to the project.json dependencies. Now that we have added ‘axios’ we can modify the gatsby-node.js file so that the sourceNodes function looks like the following;

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.com/docs/node-apis/
 */
// You can delete this file if you're not using it

/**
 * You can uncomment the following line to verify that
 * your plugin is being loaded in your site.
 *
 * See: https://www.gatsbyjs.com/docs/creating-a-local-plugin/#developing-a-local-plugin-that-is-outside-your-project
 */
const axios = require('axios');

exports.onPreInit = () => console.log("Loaded ships");

// constants for your GraphQL Post and Author types
const SHIP_NODE_TYPE = `Ship`;

exports.sourceNodes = async ({
  actions,
  createContentDigest,
  createNodeId,
  getNodesByType,
}) => {
  const { createNode } = actions

    let shipsleft = true;
    let currentpage = 1;
    let ships = [];

    while (shipsleft) {
        let shippages = await getShipsPage(currentpage); 
        ships.push(...shippages.results);
        if (!shippages?.next) {
            shipsleft = false;
        } else {
            currentpage++;
        }
    }
    
  // loop through data and create Gatsby nodes
  ships.forEach(ship =>
    createNode({
      ...ship,
      id: createNodeId(`${SHIP_NODE_TYPE}-${ship.name}`),
      parent: null,
      children: [],
      internal: {
        type: SHIP_NODE_TYPE,
        content: JSON.stringify(ship),
        contentDigest: createContentDigest(ship),
      },
    })
  )

  return
}

async function getShipsPage(page = 1) {
    const ships = await axios.get(`https://swapi.dev/api/starships/?page=${page}`);
    return ships.data;
}

We have modified the ‘gatsby-node.js’ file in the plugin so that it queries all of the ships in the Star Wars API, and adds nodes for each ship. We now test that the plugin is adding the nodes by using the GraphQL by running gatsby develop command and doing a query against the GraphiQL tool at [http://localhost:8000/___graphql].

Try making the following query in graphiql;

query MyQuery {
  allShip {
    edges {
      node {
        id
        name
        model
      }
    }
  }
}

Using this data in our Site

Now that we have the plugin querying data, we can use it to query data and display it on our Homepage. Lets’ modify the ‘index.js’ file so that it uses GraphQL to query the data from our plugin;

import React from "react"
import { graphql } from "gatsby"

const HomePage = ({ data }) => {
  console.log(data);
  return (
    <>
      <h1>Ships</h1>
      {data.allShip.edges.map(ship => (
        <div id={ship.node.id}>
          <h3>{ship.node.name}</h3>
          <p>Model: {ship.node.model}</p>
          <p>hyperdrive_rating: {ship.node.hyperdrive_rating}</p>
        </div>
      ))}
    </>)
};

export const query = graphql`
  query {
    allShip {
      edges {
        node {
          id
          name
          model
          passengers
          crew
          hyperdrive_rating
          manufacturer
          starship_class
          url
        }
      }
    }
  }
`

export default HomePage;

As you can see from the above example we are importing in ‘graphql’, creating a query to get our ship data, then outputting through the ‘data’ de-constructor in the HomePage function.

Conclusion

Gatsby makes it very easy to extend the built in functionality to import data through the use of source plugins. Combined with the power of GraphQL, we can now easily add new data sources to our Gatsby sites.