使用React和Apollo来试用Github的GraphQL API

Livesense的第二篇《Advent Calendar 2016 – Qiita》的24号文章。现在我正在写这篇文章的时候已经是25号了(;・∀・)。

我会使用Apollo作为GraphQL客户端库来解释如何使用GraphQL API的示例代码。

因为Apollo也有示例代码,但是必须自己搭建服务器,非常麻烦。所以,通过方便地使用Github的GraphQL API,我认为可以了解一下这种感觉。

GraphQL是什么?

这个链接里的Qiita上有一篇关于GraphQL入门的文章,你可以参考一下。

源代码

在进行操作之前,请按照安装说明中所写的来进行设置。首先,需要在上述提到的Github的 Early Access Program 上注册,并按照“Creating an access token guide”获取一个访问令牌。请将该访问令牌保存至 config.secret.js 中。

请不要将此代码直接上传到互联网或在生产环境中使用类似的写法,因为此代码只是一个示例,直接包含了GitHub访问令牌在客户端代码中。

关于阿波罗

这次我们使用了Apollo这个GraphQL客户端库,其中使用了Apollo提供的适用于JavaScript的apollo-client(还有适用于Swift和Android的客户端)。此外,示例中使用了React,但也提供了与React绑定的工具,可以无缝地连接React组件和GraphQL。

尽管有一个由Facebook开发的名为Relay的GraphQL React客户端库,但是由于Relay的查询格式与标准GraphQL的格式不同,我们决定使用Apollo来完成这个需求。

解析示例代码

GraphQL查询

以下是GraphQL查询的部分。

import gql from 'graphql-tag'
 :
const RepositorySearchQuery = gql`
  query Search($q: String!) {
    search(query: $q, first: 10, type: REPOSITORY) {
      edges {
        node {
          ... on Repository {
            id,
            name,
            url
          }
        }
      }
    }
  }
`

gql是Apollo提供的用于表示GraphQL查询的库函数,查询主体位于“quer Search($q: String!) {…}”的部分。这个描述的意象就像直接写SQL一样。这部分可以直接传递给GraphQL的GUI客户端,实际上,操作下面的结果会得到如下所示的结果。

image

用于连接API的客户端


import ApolloClient, { createNetworkInterface } from 'apollo-client'
  :
const networkInterface = createNetworkInterface({ uri: 'https://api.github.com/graphql' }) // (1)
networkInterface.use([{ // (2)
  applyMiddleware(req, next) {
    if (!req.options.headers) {
      req.options.headers = {
    }
    req.options.headers.authorization = `bearer ${githubToken}`
    next()
  }
}])
const client = new ApolloClient({ // (1)
  networkInterface: networkInterface,
})

创建连接到API的客户端,步骤如上。

使用helper函数createNetworkInterface生成NetworkInterface对象,并将其传递给client(1)。

createNetworkInteface函数会默认生成一个用于访问同一域名下的/graphql路径的NetworkInteface对象,所以若要连接到其他域名的API或者当前GraphQL路径非/graphql的情况下,需要指定uri选项。

此外,如果像Github API那样需要在HTTP请求中添加Authorization头部的情况下,可以通过NetworkInterface的use方法来添加一个用于在HTTP请求头部中添加Authorization头部的中间件(2)。(就像express一样,NetworkInterface可以使用use方法来叠加用于拦截HTTP请求的中间件)

将React组件与GraphQL进行集成


import { ApolloProvider, graphql } from 'react-apollo'
  :
class Repositories extends Component { // (3)
  render() {
    let repos = []
    let h1Text = `Searching For ${this.props.query} ...`

    if (this.props.data && this.props.data.search) {  // (5)
      h1Text = `Repositories about ${this.props.query} are`
      repos = this.props.data.search.edges.map(edge => ({
        key: edge.node.id,
        name: edge.node.name,
        url: edge.node.url
      }))
    }

    return (
      <div>
        <h1>{h1Text}</h1>
        <ul>
          {repos.map(repo => <Repository key={repo.key} name={repo.name} url={repo.url} />)}
        </ul>
      </div>
    )    
  }
}

class App extends Component {
  :
  :
  handleFormSubmit(evnt) {
    evnt.preventDefault()

    const RepositoriesWithQuery = graphql(RepositorySearchQuery, {  // (4)
      options: {variables: { q: this.state.q }}
    })(Repositories)

    this.setState({
      repositories: <RepositoriesWithQuery query={this.state.q} />
    })

  }
  :
  render() {
    return (
      <div>
        <SearchForm onSubmit={evnt => this.handleFormSubmit(evnt)} onChange={evnt => this.handleTextChange(evnt)} />
        <ApolloProvider client={client}> // (6)
          {this.state.repositories}
        </ApolloProvider>
      </div>
    )
  }
}

这个React组件与(3)的存储库现在与GraphQL相关联。

通过graphql函数(由react-apollo提供的辅助函数)将其与GraphQL查询关联起来,就像(4)中那样。具体来说,graphql函数返回的结果也是React组件,该组件通过props将从API获取的数据传递给此组件,这样就能在Component中传播数据,如(5)所示。通过props.data,GraphQL的结果将传递过来。由于props.data以下的结构完全与从GraphQL API返回的JSON结构相同,因此您可以访问GUI客户端捕获的数据并以相同的结构获取所需的数据。而且,GraphQL的获取是异步执行的,因此与组件的初次渲染时间不同,所以通过对数据的存在与否进行条件分支判断(虽然我认为还有更好的写法,但这是一个示例代码嘛)。

最后是ApolloProvider组件,这是由react-apollo提供的,对于使用图书馆的用户来说,相当于一个魔法咒语。必须将它与GraphQL组件相关联,并将其放置在ApolloProvider组件的下方,这样才能正确地获取结果。

应该会像这样多分动起来吧…

最终最后

由于关于GraphQL的日语文章不是很多,所以我认为它并没有引起太多的关注,但如果在本文中有错误或奇怪的解释,请您指正。我希望GraphQL能在日本更加普及,所以我打算在未来继续撰写相关文章。谢谢。

无法连接到FunctionalComponent。↩

实际上,props.data中包含了GraphQL结果JSON的信息以及一些元数据和函数。另外,您可以通过将选项传递给graphql函数来修改props.data的结构。详细信息请参阅Apollo的文档。↩

bannerAds