通过React调用GitHub API来更新自己的个人简介和状态

首先

我想通过调用GitHub提供的GitHub REST API和GitHub GraphQL API,
在确认REST API和GraphQL API的差异的同时,
更新我的个人简介和状态。

环境建设

我会主动进行环境搭建而不使用create-react-app(感觉会学到更多)。

$ node -v
v16.13.0

$ npm -v
8.1.0

$ mkdir github-api
$ cd github-api

$ npm init -y
$ npm i react react-dom typescript
$ npm i -D webpack-cli webpack-dev-server html-webpack-plugin babel-loader @babel/preset-env @babel/preset-react @babel/preset-typescript @types/react @types/react-dom

$ gibo dump Node macOS >> .gitignore

$ npx tsc --init

// ローカルサーバ起動
$ npx webpack serve
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development",
  entry: './src/App.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  resolve: {
    extensions: [".js", ".ts", ".tsx"],
  },
  module: {
    rules: [
      {
        test: [/\.ts$/, /\.tsx$/],
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src/index.html")
    })
  ],
  devServer: {
    static: {
      directory: path.join(__dirname, "dist"),
    },
  },
};
module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    '@babel/preset-typescript'
  ],
  targets: '> 1.5%, last 2 versions, not dead',
};
{
  一部省略

  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "typescript": "^4.5.2"
  },
  "devDependencies": {
    "@babel/preset-env": "^7.16.4",
    "@babel/preset-react": "^7.16.0",
    "@babel/preset-typescript": "^7.16.0",
    "@types/react": "^17.0.37",
    "@types/react-dom": "^17.0.11",
    "babel-loader": "^8.2.3",
    "html-webpack-plugin": "^5.5.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.6.0"
  }
}
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

GitHub API 摘要

使用两种类型的API来更新GitHub的个人简介和状态。

token_scopes.png

使用GitHub的REST API进行实现。

根据GitHub文档,建议指定REST API的版本。

建议通过 Accept 头明确请求此版本,否则默认情况下,所有请求将接收到 REST API 的 v3 版本,目标地址为https://api.github.com。

所以,使用fetch进行请求的代码如下:

import React, { useState, FormEvent } from "react";

export const Rest = () => {
  const token = '作成した個人アクセストークン';
  const [data, setData] = useState();
  const [bio, setBio] = useState<string>("");
  const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    fetch('https://api.github.com/user', {
      method: "PATCH",
      body: JSON.stringify({ bio }),
      // 上記は、body: JSON.stringify({ 'bio': bio }), と等価
      headers: {
        Accept: "application/vnd.github.v3+json",
        Authorization: `bearer ${token}`,
      },
    })
      .then(res => res.json())
      .then(setData)
      .catch(console.error)
  }

  return (
    <>
      <h1>GitHub REST API で bioを更新</h1>
      <form onSubmit={handleSubmit}>
        <textarea onChange={e => setBio(e.target.value)} cols={50} rows={3} placeholder="your bio..." required />
        <button>更新する</button>
      </form>
      {data && <p>{`bioを「${data["bio"]}」に更新しました。`}</p>}
    </>
  )
}

由于这只是一个演示,所以我们直接编写了访问令牌。但实际上,最好是将令牌写入.env文件,将该文件放置在根目录下,并使用像dotenv-webpack这样的插件,以在webpack编译时导入.env文件中写的环境变量。
(如果使用create-react-app创建了React项目,则似乎已预先安装了dotenv包,该包用于设置环境变量。)

import React from "react";
import ReactDOM from "react-dom";

import { Rest } from "./rest";

ReactDOM.render(
  <React.StrictMode>
    <Rest />
  </React.StrictMode>,
  document.getElementById('root')
);
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>GitHub API test</title>
</head>
<body>
    <div id="root" />
</body>
</html>
qiita_3.gif

使用GitHub GraphQL API进行实现.

接下来,我们将使用GraphQL API来更新GitHub的状态。
似乎可以更新状态的消息和表情符号。
与REST API的不同之处,主要在于它具有一个单一的端点。

GraphQL的端点
REST API有许多端点,但GraphQL API只有一个端点。
https://api.github.com/graphql
不管所执行的操作是什么,端点始终保持不变。

我打算使用fetch来传递查询和变量给请求的body,而不使用用于React的GraphQL库等。参考以下内容。

import React, { useState, FormEvent } from "react";

export const Graphql = () => {
  const token = '作成した個人アクセストークン';
  const [data, setData] = useState();
  const [message, setMessage] = useState<string>("");
  const [emoji, setEmoji] = useState<string>("");
  const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    fetch('https://api.github.com/graphql', {
      method: "POST",
      body: JSON.stringify({
        query: `
          mutation updateStatusMutation($message: String!, $emoji: String!) {
            changeUserStatus(input: {message: $message, emoji: $emoji}) {
              status {
                message
                emoji
              }
            }
          }
        `,
        variables: {message, emoji}
      }),
      headers: {
        Authorization: `bearer ${token}`,
      },
    })
      .then(res => res.json())
      .then(setData)
      .catch(console.error)
  };

  return (
    <>
      <h1>GitHub GraphQL API で statusを更新</h1>
      <form onSubmit={handleSubmit}>
        <textarea onChange={e => setMessage(e.target.value)} cols={50} rows={2} placeholder="your status message..." required />
        <input type="text" onChange={e => setEmoji(e.target.value)} placeholder="your status emoji..." required />
        <button>更新する</button>
      </form>
      {data && <p>{`ステータスメッセージを「${data["data"]["changeUserStatus"]["status"]["message"]}」、ステータスの絵文字を「${data["data"]["changeUserStatus"]["status"]["emoji"]}」に更新しました。`}</p>}
    </>
  )
}

App.tsx和index.html与上面的内容相同。

qiita_graphql.gif

概括

最终目录的结构就像这样。

$ tree -I "node_modules|README.md|.gitignore" -L 2
.
├── babel.config.js
├── dist
│   ├── bundle.js
│   └── bundle.js.LICENSE.txt
├── package-lock.json
├── package.json
├── src
│   ├── App.tsx
│   ├── graphql.tsx
│   ├── index.html
│   └── rest.tsx
├── tsconfig.json
└── webpack.config.js

顺便一提、、

<textarea onChange={e => setBio(e.target.value)} ...以下省略 />

查看这段代码,我认为每次在textarea中输入时,组件会重新渲染。
然而,当我在读React的书时,书中提到React内部有一种机制来协调重复的渲染请求,所以不必担心不必要的重新渲染。
然而,由于函数本身会在每次输入时调用,所以应该避免在此渲染函数中执行重度处理。

希望这是我个人的备忘录,如果对他人有所帮助,我会感到幸福。

bannerAds