Creating a Source Plugin

In this section, we will learn to how to create a source plugin to pull data from REST API that exposes pokemon data: https://pokemon-json.herokuapp.com/.

The lesson you learnt here is transerable to any REST API that you created yourself or provided by any third-party.

Create a Local Plugin

bash
mkdir -p plugins/gatsby-source-pokemon
cd plugins/gatsby-source-pokemon
npm init --y
touch gatsby-node.js
bash
mkdir -p plugins/gatsby-source-pokemon
cd plugins/gatsby-source-pokemon
npm init --y
touch gatsby-node.js
plugins/gatsby-source-pokemon/gatsby-node.js
js
exports.sourceNodes = async ({ reporter }, configOptions) => {
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
};
plugins/gatsby-source-pokemon/gatsby-node.js
js
exports.sourceNodes = async ({ reporter }, configOptions) => {
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
};
gatsby-config.js
js
module.exports = {
plugins: [
'gatsby-plugin-sass',
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'src',
path: `${__dirname}/src`,
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'blogs',
path: `${__dirname}/blogs`,
},
},
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 700,
},
},
],
},
},
'gatsby-plugin-sharp',
'gatsby-transfomer-sharp',
{
resolve: 'gatsby-source-instagram',
options: {
username: 'malcolm__kee',
},
},
{
resolve: 'gatsby-source-pokemon',
options: {
x: 'y',
},
},
],
};
gatsby-config.js
js
module.exports = {
plugins: [
'gatsby-plugin-sass',
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'src',
path: `${__dirname}/src`,
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'blogs',
path: `${__dirname}/blogs`,
},
},
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 700,
},
},
],
},
},
'gatsby-plugin-sharp',
'gatsby-transfomer-sharp',
{
resolve: 'gatsby-source-instagram',
options: {
username: 'malcolm__kee',
},
},
{
resolve: 'gatsby-source-pokemon',
options: {
x: 'y',
},
},
],
};
bash
npm start
bash
npm start

Create a Source Plugin

Retrive data from API

bash
cd plugins/gatsby-source-pokemon
npm i node-fetch
bash
cd plugins/gatsby-source-pokemon
npm i node-fetch
plugins/gatsby-source-pokemon/gatsby-node.js
js
const fetch = require('node-fetch');
exports.sourceNodes = async ({ reporter }, configOptions) => {
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
const pokemons = await fetch('https://pokemon-json.herokuapp.com/api/pokedex').then((res) =>
res.json()
);
console.log(pokemons);
};
plugins/gatsby-source-pokemon/gatsby-node.js
js
const fetch = require('node-fetch');
exports.sourceNodes = async ({ reporter }, configOptions) => {
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
const pokemons = await fetch('https://pokemon-json.herokuapp.com/api/pokedex').then((res) =>
res.json()
);
console.log(pokemons);
};

Create a data node

plugins/gatsby-source-pokemon/gatsby-node.js
js
const fetch = require('node-fetch');
exports.sourceNodes = async (
{ actions, createNodeId, createContentDigest, reporter },
configOptions
) => {
const { createNode } = actions;
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
const pokemons = await fetch('https://pokemon-json.herokuapp.com/api/pokedex').then((res) =>
res.json()
);
pokemons.forEach((pokemon) => {
const nodeId = createNodeId(`pokemon-${pokemon.id}`);
const nodeContent = JSON.stringify(pokemon);
const nodeData = Object.assign({}, pokemon, {
id: nodeId,
parent: null,
children: [],
internal: {
type: 'Pokemon',
content: nodeContent,
contentDigest: createContentDigest(pokemon),
},
});
createNode(nodeData);
});
};
plugins/gatsby-source-pokemon/gatsby-node.js
js
const fetch = require('node-fetch');
exports.sourceNodes = async (
{ actions, createNodeId, createContentDigest, reporter },
configOptions
) => {
const { createNode } = actions;
reporter.info(`In gatsby-source-pokemon with the following configOptions`);
reporter.info(JSON.stringify(configOptions));
const pokemons = await fetch('https://pokemon-json.herokuapp.com/api/pokedex').then((res) =>
res.json()
);
pokemons.forEach((pokemon) => {
const nodeId = createNodeId(`pokemon-${pokemon.id}`);
const nodeContent = JSON.stringify(pokemon);
const nodeData = Object.assign({}, pokemon, {
id: nodeId,
parent: null,
children: [],
internal: {
type: 'Pokemon',
content: nodeContent,
contentDigest: createContentDigest(pokemon),
},
});
createNode(nodeData);
});
};

You can now query the pokemon data with GraphQL in Gatsby:

graphql
{
allPokemon {
edges {
node {
id
name {
english
}
base {
HP
Attack
}
image
sprite
}
}
}
}
graphql
{
allPokemon {
edges {
node {
id
name {
english
}
base {
HP
Attack
}
image
sprite
}
}
}
}

Create a page to display the data

bash
touch src/pages/pokemons.js
bash
touch src/pages/pokemons.js
src/pages/pokemons.js
jsx
import { graphql } from 'gatsby';
import * as React from 'react';
import { Layout } from '../components/layout';
const AllPokemonsPage = ({ data }) => {
const pokemons = data.allPokemon.edges.map(({ node }) => node);
return (
<Layout>
<table>
<tbody>
{pokemons.map((pokemon) => (
<tr key={pokemon.id}>
<td>
<img src={pokemon.sprite} alt={pokemon.name.english} />
</td>
<td>
<p>{pokemon.name.english}</p>
<p>Base HP: {pokemon.base.HP}</p>
<p>Base Atk: {pokemon.base.Attack}</p>
</td>
<td>
<img src={pokemon.image} alt={pokemon.name.english} />
</td>
</tr>
))}
</tbody>
</table>
</Layout>
);
};
export default AllPokemonsPage;
export const query = graphql`
query AllPokemonQuery {
allPokemon {
edges {
node {
id
name {
english
}
base {
HP
Attack
}
image
sprite
}
}
}
}
`;
src/pages/pokemons.js
jsx
import { graphql } from 'gatsby';
import * as React from 'react';
import { Layout } from '../components/layout';
const AllPokemonsPage = ({ data }) => {
const pokemons = data.allPokemon.edges.map(({ node }) => node);
return (
<Layout>
<table>
<tbody>
{pokemons.map((pokemon) => (
<tr key={pokemon.id}>
<td>
<img src={pokemon.sprite} alt={pokemon.name.english} />
</td>
<td>
<p>{pokemon.name.english}</p>
<p>Base HP: {pokemon.base.HP}</p>
<p>Base Atk: {pokemon.base.Attack}</p>
</td>
<td>
<img src={pokemon.image} alt={pokemon.name.english} />
</td>
</tr>
))}
</tbody>
</table>
</Layout>
);
};
export default AllPokemonsPage;
export const query = graphql`
query AllPokemonQuery {
allPokemon {
edges {
node {
id
name {
english
}
base {
HP
Attack
}
image
sprite
}
}
}
}
`;