49

I am new in both React and GatsbyJS. I am confused and could not make figuring out in a simple way to load data from third-party Restful API.

For example, I would like to fetch data from randomuser.me/API and then be able to use the data in pages.

Let’s say something like this :

  import React from 'react'
  import Link from 'gatsby-link'

  class User extends React.Component {
    constructor(){
      super();
      this.state = {
        pictures:[],
      };

    }

    componentDidMount(){
      fetch('https://randomuser.me/api/?results=500')
      .then(results=>{
        return results.json();
      })
      .then(data=>{
        let pictures = data.results.map((pic,i)=>{
            return(
              <div key={i} >
                <img key={i} src={pic.picture.medium}/>
              </div>
            )
        })
        this.setState({pictures:pictures})
      })
    }

    render() {
      return (<div>{this.state.pictures}</div>)
    }
  }

  export default User;

But I would like to get the help of GraphQL in order to filter & sort users and etc…..

Could you please help me to find the sample to how I can fetch data and insert them into GraphQL on gatsby-node.js?

Rafael Corrêa Gomes
  • 1,751
  • 1
  • 22
  • 31
AJ-
  • 1,027
  • 2
  • 13
  • 24
  • 5
    You cannot use GatsbyJS's GraphQL interface at runtime, only at build time. You can, however, use a third party library for that if you really need GraphQL. – Miguel Calderón Mar 15 '18 at 13:29
  • 2
    Thanks for your PM. but I am not looking to make runtime GraphQL, for a better explanation, I check this example https://github.com/gatsbyjs/gatsby/tree/master/examples/using-contentful . , but this is only customised to specific API from contentful , there I would like to build a similar example to load data from any Restful API . I check the GatsbyJS plugin section , there is plugin 'gatsby-source-api' but I could not make it work or run in my sample application – AJ- Mar 15 '18 at 15:02
  • Those plugins and examples are intended to be used at build time (not on `componentDidMount()`, not with `fetch`, I'm not sure if I explain myself clearly). I'm afraid for the moment there isn't a generic plugin to use for customized REST API calls. – Miguel Calderón Mar 15 '18 at 15:16

5 Answers5

94

If you want to use GraphQL to fetch your data, you have to create a sourceNode. The doc about creating a source plugin could help you.

Follow these steps to be able to query randomuser data with GraphQL in your Gatsby project.

1) Create nodes in gatsby-node.js

In your root project folder, add this code to gatsby-node.js:

const axios = require('axios');
const crypto = require('crypto');

exports.sourceNodes = async ({ actions }) => {
  const { createNode } = actions;

  // fetch raw data from the randomuser api
  const fetchRandomUser = () => axios.get(`https://randomuser.me/api/?results=500`);
  // await for results
  const res = await fetchRandomUser();

  // map into these results and create nodes
  res.data.results.map((user, i) => {
    // Create your node object
    const userNode = {
      // Required fields
      id: `${i}`,
      parent: `__SOURCE__`,
      internal: {
        type: `RandomUser`, // name of the graphQL query --> allRandomUser {}
        // contentDigest will be added just after
        // but it is required
      },
      children: [],

      // Other fields that you want to query with graphQl
      gender: user.gender,
      name: {
        title: user.name.title,
        first: user.name.first,
        last: user.name.last,
      },
      picture: {
        large: user.picture.large,
        medium: user.picture.medium,
        thumbnail: user.picture.thumbnail,
      }
      // etc...
    }

    // Get content digest of node. (Required field)
    const contentDigest = crypto
      .createHash(`md5`)
      .update(JSON.stringify(userNode))
      .digest(`hex`);
    // add it to userNode
    userNode.internal.contentDigest = contentDigest;

    // Create node with the gatsby createNode() API
    createNode(userNode);
  });

  return;
}

I used axios to fetch data so you will need to install it: npm install --save axios

Explanation:

The goal is to create each node for each piece of data you want to use. According to the createNode documentation, you have to provide an object with few required fields (id, parent, internal, children).

Once you get the results data from the randomuser API, you just need to create this node object and pass it to the createNode() function.

Here we map to the results as you wanted to get 500 random users https://randomuser.me/api/?results=500.

Create the userNode object with the required and wanted fields. You can add more fields depending on what data you will want to use in your app.

Just create the node with the createNode() function of the Gatsby API.

2) Query your data with GraphQL

Once you did that, run gatsby develop and go to http://localhost:8000/___graphql.

You can play with GraphQL to create your perfect query. As we named the internal.type of our node object 'RandomUser', we can query allRandomUser to get our data.

{
  allRandomUser {
    edges {
      node {
        gender
        name {
          title
          first
          last
        }
        picture {
          large
          medium
          thumbnail
        }
      }
    }
  }
}

3) Use this query in your Gatsby page

In your page, for instance src/pages/index.js, use the query and display your data:

import React from 'react'
import Link from 'gatsby-link'

const IndexPage = (props) => {
  const users = props.data.allRandomUser.edges;

  return (
    <div>
      {users.map((user, i) => {
        const userData = user.node;
        return (
          <div key={i}>
            <p>Name: {userData.name.first}</p>
            <img src={userData.picture.medium} />
          </div>
        )
      })}
    </div>
  );
};

export default IndexPage

export const query = graphql`
  query RandomUserQuery {
    allRandomUser {
      edges {
        node {
          gender
          name {
            title
            first
            last
          }
          picture {
            large
            medium
            thumbnail
          }
        }
      }
    }
  }
`;

That is it!

Winston
  • 1,308
  • 5
  • 16
  • 34
Nenu
  • 2,637
  • 1
  • 18
  • 24
  • What if I want to fetch data from my personal Database? I mean, deploying the app in production I cannot leave in the gatsby-node.js file the url `https://randomuser.me/api`...it should be connected with the server (for instance, Express) that is set up. I tried to add a proxy in the package.json matching the server address but it won't work – Enrico Nov 06 '18 at 12:07
  • 1
    @Enrico I would say you should first check if there is a gatsby plugin available to connect to your database. Otherwise, you can create your own REST api with Express, something like `app.get("/api-url", (req, res, next) => { /*get data*/ res.json(data) })`. Then you will be able to use your api urls into your **gatsby-node.js** file: `https://myapp.com/api-url`. – Nenu Nov 08 '18 at 06:51
  • 1
    @AidanGrimshaw As far as I know, `gatsby-node.js` is only executed at **build** time. So the answer would be no, this would not update at runtime – Nenu Jun 25 '19 at 16:21
  • This would make for a great Gatsby tutorial, thank you! – Robin Métral Nov 02 '19 at 23:23
  • 2
    Can someone please update this for 2020? I tried it but crypto is no longer supported https://www.npmjs.com/package/crypto – Richard Reis Jan 06 '20 at 01:12
  • Can I use this for POST request too? – Md Abdul Halim Rafi Feb 02 '20 at 19:22
5

Many thanks, this is working fine for me, I only change small parts of the gastbyjs-node.js because it makes an error when use sync & await, I think I need change some section of a build process to use babel to allow me to use sync or await.

Here is the code which works for me.

 const axios = require('axios');
 const crypto = require('crypto');

 // exports.sourceNodes = async ({ boundActionCreators }) => {
 exports.sourceNodes = ({boundActionCreators}) => {
const {createNode} = boundActionCreators;
return new Promise((resolve, reject) => {

// fetch raw data from the randomuser api
// const fetchRandomUser = () => axios.get(`https://randomuser.me/api/?results=500`);
// await for results
// const res = await fetchRandomUser();

axios.get(`https://randomuser.me/api/?results=500`).then(res => {

  // map into these results and create nodes
  res.data.results.map((user, i) => {

    // Create your node object
    const userNode = {
      // Required fields
      id: `${i}`,
      parent: `__SOURCE__`,
      internal: {
        type: `RandomUser`, // name of the graphQL query --> allRandomUser {}
        // contentDigest will be added just after
        // but it is required
      },
      children: [],

      // Other fields that you want to query with graphQl
      gender: user.gender,
      name: {
        title: user.name.title,
        first: user.name.first,
        last: user.name.last
      },
      picture: {
        large: user.picture.large,
        medium: user.picture.medium,
        thumbnail: user.picture.thumbnail
      }
      // etc...
    }

    // Get content digest of node. (Required field)
    const contentDigest = crypto.createHash(`md5`).update(JSON.stringify(userNode)).digest(`hex`);
    // add it to userNode
    userNode.internal.contentDigest = contentDigest;

    // Create node with the gatsby createNode() API
    createNode(userNode);
  });
  resolve();
});

});

}
AJ-
  • 1,027
  • 2
  • 13
  • 24
  • 1
    Since the building of nodes is done before the page is loaded (this is a static site generator, after all), you shouldn't have to worry about babel. Just make sure the version of node you're using to develop, and the node version on the service you deploy to (Netlify?) both support async/await – Roy Oct 31 '18 at 12:58
2

The accepted answer for this works great, just to note that there's a deprecation warning if you use boundActionCreators. This has to be renamed to actions to avoid this warning.

  • 4
    Hi @pixelbreaker - in the future, this likely would be better as a comment on the answer, rather than an answer. – Slabgorb Aug 16 '19 at 17:49
  • Fully agree with @Slabgorb, but still a +1 because it's a good point :) Would you mind commenting this on the accepted answer @pixelbreaker? Or even suggest an edit? – Robin Métral Nov 02 '19 at 23:25
1

The answers given above work, except the query in step 2 seems to only return one node for me. I can return all nodes by adding totalCount as a sibling of edges. I.e.

{
  allRandomUser {
    totalCount
    edges {
      node {
        id
        gender
        name {
          first
          last
        }
      }
    }
  }
}
Rafael Corrêa Gomes
  • 1,751
  • 1
  • 22
  • 31
scaganoff
  • 1,830
  • 1
  • 16
  • 19
1

You can get data at the frontend from APIs using react useEffect. It works perfectly and you will no longer see any error at builtime

 const [starsCount, setStarsCount] = useState(0)
  useEffect(() => {
    // get data from GitHub api
    fetch(`https://api.github.com/repos/gatsbyjs/gatsby`)
      .then(response => response.json()) // parse JSON from request
      .then(resultData => {
        setStarsCount(resultData.stargazers_count)
      }) // set data for the number of stars
  }, [])
Ericgit
  • 6,089
  • 2
  • 42
  • 53