GatsbyJS 如何从 Restful API 中获取数据

50

我对React和GatsbyJS都很新,感到困惑,并且无法简单地弄清楚如何从第三方Restful API加载数据。

例如,我想从randomuser.me/API获取数据,然后能够在页面中使用这些数据。

假设像这样:

  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;

但我希望能借助GraphQL来过滤和排序用户等信息......

您能否帮助我找到如何在gatsby-node.js中获取数据并将其插入GraphQL的示例?


5
你不能在运行时使用 GatsbyJS 的 GraphQL 接口,只能在构建时使用。然而,如果你真的需要 GraphQL,可以使用第三方库。 - Miguel Calderón
2
谢谢您的私信。但我不想制作运行时GraphQL,为了更好的解释,我查看了这个例子 https://github.com/gatsbyjs/gatsby/tree/master/examples/using-contentful 。但这只是针对Contentful特定API的自定义,我想构建一个类似的示例来从任何Restful API中加载数据。我检查了GatsbyJS插件部分,有一个名为“gatsby-source-api”的插件,但我无法使其在我的示例应用程序中工作或运行。 - AJ-
这些插件和示例旨在在构建时使用(而不是在componentDidMount()中,也不是与fetch一起使用,我不确定我是否表达清楚)。恐怕目前还没有通用的插件可用于自定义REST API调用。 - Miguel Calderón
5个回答

94

如果您想使用GraphQL获取数据,必须创建一个sourceNode。有关创建源插件的文档可以帮助您。

按照以下步骤,在Gatsby项目中使用GraphQL查询randomuser数据。

1)在gatsby-node.js中创建节点

在您的根项目文件夹中,将以下代码添加到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;
}

我使用了axios来获取数据,所以你需要安装它:npm install --save axios

Explanation:

目标是为要使用的每个数据创建一个节点。 根据createNode文档,您必须提供一个具有几个必需字段(id、parent、internal、children)的对象。

一旦您从randomuser API获得结果数据,您只需创建此节点对象并将其传递给createNode()函数。

在这里,我们按照您想要获取500个随机用户的结果进行映射https://randomuser.me/api/?results=500

使用所需和想要的字段创建userNode对象。您可以添加更多字段,具体取决于您想在应用程序中使用的数据。

只需使用Gatsby API的createNode()函数创建节点。

2) 使用GraphQL查询数据

完成后,运行gatsby develop并转到http://localhost:8000/___graphql

您可以使用GraphQL来创建完美的查询。由于我们将节点对象的internal.type命名为'RandomUser',因此我们可以查询allRandomUser来获取我们的数据。

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

3) 在Gatsby页面中使用此查询

在您的页面中,例如src/pages/index.js,使用此查询并显示您的数据:

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
          }
        }
      }
    }
  }
`;

就是这样!


如果我想从我的个人数据库中获取数据怎么办?我的意思是,在生产环境中部署应用程序时,我不能在gatsby-node.js文件中留下url https://randomuser.me/api...它应该连接到已设置的服务器(例如Express)。我尝试在package.json中添加代理以匹配服务器地址,但它不起作用。 - Enrico
1
@Enrico,我建议你首先检查是否有可用的Gatsby插件来连接你的数据库。否则,你可以使用Express创建自己的REST API,类似于 app.get("/api-url", (req, res, next) => { /*获取数据*/ res.json(data) })。然后,你就可以在你的 gatsby-node.js 文件中使用你的API URL:https://myapp.com/api-url - Nenu
1
据我所知,gatsby-node.js仅在构建时执行。因此答案是否定的,它不会在运行时更新。 - Nenu
这将是一个很棒的 Gatsby 教程,谢谢! - Robin Métral
2
有人可以请更新一下这个到2020年吗?我尝试了,但是加密已不再受支持。https://www.npmjs.com/package/crypto - Richard Reis
我可以用这个来发送POST请求吗? - Md Abdul Halim Rafi

5
非常感谢,这对我很有用,我只更改了gatsbyjs-node.js的一小部分,因为在使用同步和等待时会出现错误,我认为我需要更改一些构建过程的部分来使用Babel,以便让我使用同步或等待。
以下是适用于我的代码。
 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();
});

});

}

1
由于节点的构建是在页面加载之前完成的(毕竟这是一个静态站点生成器),因此您不必担心babel。只需确保您用于开发的节点版本和您部署到的服务(Netlify?)上的节点版本都支持async/await即可。 - Roy

2
你可以使用react的useEffect从API获取前端数据。它可以完美地工作,而且在构建时不会出现任何错误。
 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
  }, [])

2

这个最初的回答很好,只是需要注意,如果你使用boundActionCreators会有一个弃用警告。为了避免这个警告,必须将其重命名为actions


4
你好 @pixelbreaker - 未来最好将此作为评论发表在答案下,而不是作为答案。 - Slabgorb
完全同意@Slabgorb的观点,但仍然给一个+1因为这是一个好的观点 :) 你介意在被接受的回答@pixelbreaker下发表评论吗?或者甚至提出修改建议? - Robin Métral

1
以上给出的答案是可行的,但是在第二步中查询似乎只返回一个节点。我可以通过将totalCount作为edges的兄弟节点来返回所有节点。例如:
{
  allRandomUser {
    totalCount
    edges {
      node {
        id
        gender
        name {
          first
          last
        }
      }
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接