or

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

2019年9月27日

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

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

  • 对graphql有所了解
  • 对es6+语法有所了解
  • 对nodejs有所了解
  • 熟悉github

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

一、热身

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

二、项目初始化

  1. npm i npx -g

  2. npm init -y

  3. npm i typescript ts-node

  4. npm i apollo-link apollo-link-http apollo-link-rest graphql graphql-anywhere graphql-tag qs node-fetch

  5. npm i @types/node-fetch -D

  6. 建立tsconfig.jsonindex.ts

  7. tsconfig.json内容如下:

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

三、获取接口调用令牌

调用github的api需要使用令牌,可在token管理页面新建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
新建的gist

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

小结

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

or