使用Github的GraphQL API 建立自己的博客站点

1,608 阅读5分钟

前言

这篇文章主要介绍如何使用Github的GraphQL API来建立自己的博客站点,对GraphQL的相关的知识,不做过多的赘述。 对想尝试GraphQL,但自己暂时没有精力建立GraphQL层,或者用一种新鲜的方式建立自己的站点的朋友,我想Github GraphQL API会是一个不错的选择。✌️ PS:这里介绍到的东西 不需要你用任何数据库 因为就是要用Github做你的数据库

GraphQL与Restful API

GraphQL是一种针对图状数据进行查询的API查询语言, 在GraphQL的官方首页,它是这样介绍自己的 ———Describe your dataAsk for what you want and Get predictable result。更多的GraphQL相关的endpoint、schema和query等概念,可以查看GraphQL的官方文档

和传统的RESTful API一样,基于GraphQL的API,大部分情况下依旧是以http协议提供服务的,如Github v4的GraphQL APIhttps://api.github.com/graphql。相比传统的基于RESTful API提供的http服务, 对于使用方来说,基于GraphQL提供的服务,区别主要在于查询方式。用Restful API服务一个多请求的页面或者系统时,往往需要非常多的API接口来请求不同模块的数据;而基于GraphQL提供的API获取数据时,往往都只需要一个API接口,不同的模块需要请求什么数据,我们就描述需要的数据,这个接口会根据我们的描述,返回我们需要的数据。所以在使用基于GraphQL提供的API时,更像在使用SQL向某一个数据库进行查询。

设想一下, 如果我们要建立一个自己的博客站点,传统的RESTful API需要提供多少个不同的API接口?—— 简单罗列一下,至少需要博客分页的列表接口、每篇博客的详情接口,当然了,还有各种数不清的字段,当我们有其他需求的时候,不可避免地是服务端和终端都要新增并使用新的API接口,或者改变接口中的字段。 而GraphQL的服务只会提供一个统一的API接口,作为它的endpoint。所有的查询操作,都只依赖这一个接口进行。然后,像GraphQL官方描述的那样,在请求体中,describe your data, ask for what you want and get predictable result👍。

如何使用Github GraphQL API

Github为自己的GraphQL API提供了非常详细的文档,在文档中,我们可以方便地看到如何使用Github的GraphQL API来查询。

首先和上文提到的一样,Github的GraphQL对外同样只提供了一个http接口,即https://api.github.com/graphql

获取token

在使用这个http接口的时候,我们必须使用自己的token进行鉴权操作,否则请求会不出所料地返回401 Unauthorized的错误。如何获取这个token呢,可以从developer setting获取。 image.png 在获得token之后,就可以将其注入到GraphQL API的请求中,随后,我们就可以尽情地使用Github提供的GraphQL服务,获取我们需要的Github上面可获取的数据 。

curl  https://api.github.com/graphql -H "Authorization: bearer token" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
"

使用Explorer

由于我们需要使用唯一的http接口请求各种各样Github上的数据,Github提供的GraphQL势必是非常复杂的,但是不用担心,我们可以使用Explorer进行“可视化”地辅助我们编写、测试我们的查询语句是否是正确且能获取我们需要的数据的。在Explorer的左侧,我们可以清楚地看到Github提供了哪些query和其对应的schema,点击时会在中间增加对应的query,当然我们也可以自己手写,当我们完成自己的查询语句时,就可以点击上方的开始箭头进行查询,查询接口会出现在右侧。

image.png

获取建立博客需要的查询语句

如上文提到的,建立自己的博客站点模块,我们至少需要获取博客文章列表,同时获取每篇博客的详情。很多人都喜欢新建一个github的仓库,并以issue作为单篇的博客。通过Explorer,我们可以很快确定可以查询某个仓库下的issue的GraphQL,

获取issue列表
query {
  viewer {
    repository(name:"blogs") { # 这里是博客所在仓库的name
      issues(first:10) {
        edges {
          node {
            title,
            createdAt
          }
        }
      }
    }
  }
}

可以返回issue的列表,这里只是展示了获取标题和创建时间的效果,如果需要其他的数据,只要schema有的都可以获取。 image

获取单个Issue内容

获取列表之后,需要获取每个issue的详情,这里可以利用另一个GraphQL来获取,

query  {
      viewer {
        repository(name: "blogs") {
          issue: issue(number: 2) { # 这里的number对应的是issue的number而不是id, 如2,即https://github.com/uyarn/blogs/issues/2
            title
            createdAt
            body
          }
        }
      }
 }

查询结果如下 image.png

在项目中使用GraphQL

确定了我们需要的GraphQL查询语句之后,就可以在项目中应用啦。我们可以使用开源的apollo来帮助完成app中graphql相关代码的编写。说到底GraphQL都只是一种标准,查询规范。apollo是基于GraphQL的实际实现,且提供了包括client端和server端的套件,开发者可以基于apollo的这些套件快速开发基于GraphQL的应用。这里我们会用到@apollo/client 的前端版本 ,以React为例进行实现。

  • 首先要在项目中安装两个依赖@apollo/client和graphql npm install @apollo/client graphql
  • 接下来要保证在项目中创建一个apollo client的实例
import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://api.github.com/graphql', // 这里是请求的endpoint
  cache: new InMemoryCache(),
  hedaders: {
    authorization: bearer ${token} // 这里的token即上文提到的github的 access token
 }
});
  • 在新建client实例之后,我们可以用它来发起请求, 以上文提到的请求issue列表为例。query会返回一个Promise对象。
import { gql } from '@apollo/client';

// const client = ...
try {
  const result = await client
  .query({
    query: gql`
      query {
         viewer {
       repository(name:"blogs") {
      issues(first:10) {
        edges {
          node {
            title,
            createdAt
          }
        }
      }
    }
  }
}`
  })
}

当然,2021年了,在React中,怎么可以不用Hooks呢,@apollo/client同样提供了基于hooks实现的方法,这里我们可以通过ApolloProvider将client实例通过Context的方式注入,包裹在App的最外层。直接使用apollo的例子

import React from 'react';
import { render } from 'react-dom';
import { ApolloProvider } from '@apollo/client/react';

const client = new ApolloClient({ uri, cache });

function App() {
  return (
    <div>
      <h2>My first Apollo app 🚀</h2>
    </div>
  );
}

render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root'),
);

接下来,在具体的列表逻辑中,可以使用useQuery的custom hooks 来执行需要的查询操作。以查询issue详情为例

import React from "react";
import ReactMarkdown from "react-markdown";
import { useQuery, gql } from "@apollo/client";

import "./index.scss";

function Article(props) {
  const issueId = props?.match?.params?.id;

  const graphql = gql`
    query {
      viewer {
        repository(name: "blogs") {
          issue1: issue(number: ${issueId}) {
            title
            createdAt
            body 
          }
        }
      }
    }
  `;
  const { loading, error, data } = useQuery(graphql);
  return (
    <div className="article">
      <ReactMarkdown>{data?.viewer?.repository?.issue1?.body}</ReactMarkdown>
    </div>
  );
}
export default Article;
  • 获取issue详情的body之后,我们可以用react-markdown将markdown渲染成html
return (
    <div className="article">
      <ReactMarkdown>{data?.viewer?.repository?.issue1?.body}</ReactMarkdown>
    </div>
  );

渲染效果如下, 具体效果,www.uyarn.me/#/article/2 预览 image.png

我的站点中的博客部分 www.uyarn.me/#/blogs 就是用github的graphql api来实现的,同步自 github.com/uyarn/uyarn… 直接使用gitub的issue来做自己的"数据存储",并利用github的graphql api将自己的文章直接同步到自己的站点~ 美滋滋


references: