前言
这篇文章主要介绍如何使用Github的GraphQL API来建立自己的博客站点,对GraphQL的相关的知识,不做过多的赘述。 对想尝试GraphQL,但自己暂时没有精力建立GraphQL层,或者用一种新鲜的方式建立自己的站点的朋友,我想Github GraphQL API会是一个不错的选择。✌️ PS:这里介绍到的东西 不需要你用任何数据库 因为就是要用Github做你的数据库
GraphQL与Restful API
GraphQL是一种针对图状数据进行查询的API查询语言, 在GraphQL的官方首页,它是这样介绍自己的 ———Describe your data,Ask 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获取。
在获得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,当然我们也可以自己手写,当我们完成自己的查询语句时,就可以点击上方的开始箭头进行查询,查询接口会出现在右侧。
获取建立博客需要的查询语句
如上文提到的,建立自己的博客站点模块,我们至少需要获取博客文章列表,同时获取每篇博客的详情。很多人都喜欢新建一个github的仓库,并以issue作为单篇的博客。通过Explorer,我们可以很快确定可以查询某个仓库下的issue的GraphQL,
获取issue列表
query {
viewer {
repository(name:"blogs") { # 这里是博客所在仓库的name
issues(first:10) {
edges {
node {
title,
createdAt
}
}
}
}
}
}
可以返回issue的列表,这里只是展示了获取标题和创建时间的效果,如果需要其他的数据,只要schema有的都可以获取。
获取单个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
}
}
}
}
查询结果如下
在项目中使用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 预览
我的站点中的博客部分 www.uyarn.me/#/blogs 就是用github的graphql api来实现的,同步自 github.com/uyarn/uyarn… 直接使用gitub的issue来做自己的"数据存储",并利用github的graphql api将自己的文章直接同步到自己的站点~ 美滋滋
references: