使用 apollo 搭配 github api 实现 gist 的获取和创建

本篇文章记录了“如何在 node 环境下采用 graphql 的形式来请求 rest 形式的接口和 graphql 形式的接口”。

阅读本篇文章,你需要有如下的知识储备:


接口平台选用 github api ,因为它既提供了 rest 接口,也提供了 graphql 接口,真是妙哉。对于 graphql 的操作我选用 apollo platform 提供的相关包,因为该平台是(我认为)目前对 graphql 解决方案提供最为完整的平台。

一、热身

使用 github 提供的 graphql explorer 来在线体验使用 graphql 请求 graphql 接口,可免去自行配置本地开发时的苦恼,方便地感受 graphql 的魅力。但由于目前 github 的 graphql 接口并未提供对 gist 的改动操作,比如新建、删除等,仅提供了获取。所以...我成功找到了一个让我去本地配置开发环境的理由,于是诞生了这篇文章。

二、项目初始化

npm i npx -g
npm init -y
npm i typescript ts-node
npm i apollo-link apollo-link-http apollo-link-rest graphql graphql-anywhere graphql-tag qs node-fetch
npm i @types/node-fetch -D

然后建立 typescript 的配置文件 tsconfig.json

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es6",
    "skipLibCheck": true,
    "noEmit": true,
    "alwaysStrict": true
  },
  "exclude": ["node_modules"]
}

三、获取接口调用令牌

调用 github 的 api 需要使用令牌,可在 token管理 页面新建 token,输入名称并选择权限,然后生成: 新建token 点击生成之后会得到 token 值,保存该值,后面会在请求时用到它。

四、请求 graphql 接口

下面是请求 github api 的 graphql接口 来获取自己创建的前两个 gist。将下述代码覆盖写入 index.ts 中并使用 npx ts-node index.ts 运行,控制台会打印我们指定的字段数据。

import { execute, makePromise, GraphQLRequest } from "apollo-link";
import { createHttpLink } from "apollo-link-http";
import gql  from "graphql-tag";
import nodeFetch from "node-fetch";

const token = '将token值写在这里(提醒:若在生成环境下,请勿将敏感信息直接写在业务代码内)';

const httpLink = new createHttpLink({
  uri: `https://api.github.com/graphql`,
  headers: {
    Authorization: `bearer ${token}`
  },
  // @ts-ignore
  fetch: nodeFetch // 解释:默认apollo在请求时是基于浏览器环境的,但node环境下并没有fetch api,因此我们需要导入一个两种环境都可用的包来代替
})

const operation: GraphQLRequest = {
  query: gql`
    query {
      viewer {
        gists(privacy: ALL, first:2) {
          edges {
            node {
              createdAt
              name 
            }
          }
        }
      }
  `
}

makePromise(execute(httpLink, operation)).then(data => {
  console.log(`data is:\n${JSON.stringify(data, null, 2)}`);
}).catch(err => {
  console.log(`error is:`);
  console.log(err);
});

代码解释:使用 graphql 的方式去请求 graphql 接口写起来是十分方便的,俺没啥要解释的。

五、请求rest接口

下面是请求 github api 的 rest接口 来新建 gist。将下述代码覆盖写入 index.ts 中并使用 npx ts-node index.ts 运行,控制台会打印我们指定的响应数据,并且去查看自己的 github gist 列表会发现新增了一个 gist。

import { execute, makePromise, GraphQLRequest } from "apollo-link";
import { RestLink } from 'apollo-link-rest'
import gql  from "graphql-tag";
import nodeFetch from "node-fetch";

// @ts-ignore
global.Headers = nodeFetch.Headers; // 这一步的作用依然是解决包运行环境问题:当apollo-link-rest运行在node端时需要设置该项,否则会报错。

const token = '将token值写在这里(提醒:若在生成环境下,请勿将敏感信息直接写在业务代码内)';

const restLink = new RestLink({
  uri: 'https://api.github.com',
  headers: {
    Authorization: `bearer ${token}`
  },
  // @ts-ignore
  customFetch: nodeFetch // 小提示:apollo-link-rest使用customFetch字段,apollo-link-http中使用fetch字段
})

const createGistOperation: GraphQLRequest = {
  query: gql`
    mutation($body: FakeNameInput) {
      createGist(body: $body) @rest(path: "/gists", method: "POST", bodyKey: "body") {
        url
      }
    }
  `,
  variables: {
    body: {
      files: {
        'test.txt': {
          content: "hello world!"
        }
      },
      description: "it's a test gist",
      "public": "false"
    }
  }
}

makePromise(execute(restLink, createGistOperation)).then(data => {
  console.log(`data is:\n${JSON.stringify(data, null, 2)}`);
}).catch(err => {
  console.log(`error is:`);
  console.log(err);
});

新建的gist

代码解释:刚开始编写这种使用 graphql 的形式请求 rest 接口时,写起来感觉真是怪怪的,但多写几次会发现它确实比普通的请求方式更易阅读甚至更易书写(个人感悟:那些初期看起来很费劲的东西,总能在后期发挥巨大潜力)。在上述代码中,我们使用 @rest 指令来表明这是在请求一个 rest 接口,该指令的参数 bodyKey 用来指明 POST 请求的 body 体数据,它的值对应了 variables 字段中的键名 (查看 文档 获取更详细说明)。

小结

突然结尾:graphql 真的很有趣 ~