GitHub REST API から Node.js で 特定の organization の issue の一覧を取得する

## コード

古い issue の一覧をチャットに通知するツールを作成しておりまして、その一環として書いたコードです。
組織（ユーザー）名、リポジトリ名はクエリパラメータに設定するなど複数パターンがあるようですが、今回は下記URLでアクセスしました。

- `[GET]  https://api.github.com/orgs/{org}/issues`

コードは下記の通りです。

```typescript
import fetch from 'isomorphic-unfetch';
import { Issue, State } from './types/vendor';

export async function get_issues(
  owner: string,
  repository: string,
  api_token: string,
  state: State  // `State`の方は`'open' | 'closed' | 'all'`です。
): Promise<Issue[]> {
  const response = await fetch(
    `https://api.github.com/repos/${owner}/${repository}/issues` +
      `?state=${state}`,
    {
      headers: {
        Authorization: `token ${api_token}`,
        Accept: 'application/vnd.github.v3+json',
      },
    }
  );
  if (response.status != 200) {
    throw new Error(
      `GitHub API にアクセスできませんでした: ${JSON.stringify(
        await response.json(),
        null,
        '  '
      )}`
    );
  }
  return (await response.json()) as Issue[];
}
```

Node.js 環境でも ブラウザ環境でも動くfetchを使用するために`isomorphic-unfetch`を使用しています。

```bash
# yarn の場合
$ yarn add isomorphic-unfetch

# npm の場合
$ npm install isomorphic-unfetch
```

`Issue`の型は QuickType で`interface`自動生成して`type`に差し替えました。
型の詳しい内容は下記の実際のソースをご確認ください。
https://github.com/sugu-sano/notify-old-issues/blob/master/src/types/vendor/isssue.ts

今回は不要でしたので設定しませんでしたが、クエリパラメータには`sort`（並び順）、`since`（指定された時間以降に更新された）もありました。詳しくは下記公式ドキュメントを参照ください。

List repository issues - GitHub Docs
https://docs.github.com/en/free-pro-team@latest/rest/reference/issues#list-repository-issues



## Octkit という GitHub 公式の REST クライアントが存在した

生の`fetch API`でアクセスしていましたが GitHub には`Octokit`という公式クライアントがありました。
また型定義も提供されていてパラメータやレスポンスの型は自作しなくてもタイプセーフに扱うことができます。

```bash
# yarn の場合
$ yarn add @octokit/core @octokit/types

# npm の場合
$ npm install @octokit/core @octokit/types
```

```typescript
import { Octokit } from "@octokit/core";
import { Endpoints } from "@octokit/types";

async function main() {
  // 型の取得の仕方に若干クセがある
  type route = "GET /repos/:owner/:repo/issues";
  type Response = Endpoints[route]["response"];
  type Parameters = Endpoints[route]["parameters"];

  const params: Parameters = {
    owner: "octocat",
    repo: "hello-world",
    since: "2020-11-20T00:00:00",
  };

  const octokit = new Octokit();
  // 戻り値が `OctokitResponse<any>` にならないように型注釈
  const response: Response = await octokit.request(
    "GET /repos/{owner}/{repo}/issues",
    params
  );

  console.log(response.data);  // `any` でなく `IssuesListForRepoResponseData` 型になる
}
main();
```

実行すると下記レスポンスが確認できました。

<details><summary>レスポンス（長いので折りたたみ）</summary><div>

```javascript
[
  {
    url: 'https://api.github.com/repos/octocat/Hello-World/issues/812',
    repository_url: 'https://api.github.com/repos/octocat/Hello-World',
    labels_url: 'https://api.github.com/repos/octocat/Hello-World/issues/812/labels{/name}',
    comments_url: 'https://api.github.com/repos/octocat/Hello-World/issues/812/comments',
    events_url: 'https://api.github.com/repos/octocat/Hello-World/issues/812/events',
    html_url: 'https://github.com/octocat/Hello-World/issues/812',
    id: 748885338,
    node_id: 'MDU6SXNzdWU3NDg4ODUzMzg=',
    number: 812,
    title: 'Test title',
    user: {
      login: 'avihlbi',
      id: 54238151,
      node_id: 'MDQ6VXNlcjU0MjM4MTUx',
      avatar_url: 'https://avatars0.githubusercontent.com/u/54238151?v=4',
      gravatar_id: '',
      url: 'https://api.github.com/users/avihlbi',
      html_url: 'https://github.com/avihlbi',
      followers_url: 'https://api.github.com/users/avihlbi/followers',
      following_url: 'https://api.github.com/users/avihlbi/following{/other_user}',
      gists_url: 'https://api.github.com/users/avihlbi/gists{/gist_id}',
      starred_url: 'https://api.github.com/users/avihlbi/starred{/owner}{/repo}',
      subscriptions_url: 'https://api.github.com/users/avihlbi/subscriptions',
      organizations_url: 'https://api.github.com/users/avihlbi/orgs',
      repos_url: 'https://api.github.com/users/avihlbi/repos',
      events_url: 'https://api.github.com/users/avihlbi/events{/privacy}',
      received_events_url: 'https://api.github.com/users/avihlbi/received_events',
      type: 'User',
      site_admin: false
    },
    labels: [],
    state: 'open',
    locked: false,
    assignee: null,
    assignees: [],
    milestone: null,
    comments: 1,
    created_at: '2020-11-23T15:13:32Z',
    updated_at: '2020-11-23T15:13:33Z',
    closed_at: null,
    author_association: 'NONE',
    active_lock_reason: null,
    body: 'Test description',
    performed_via_github_app: null
  },
  {
    url: 'https://api.github.com/repos/octocat/Hello-World/issues/810',
    repository_url: 'https://api.github.com/repos/octocat/Hello-World',
    labels_url: 'https://api.github.com/repos/octocat/Hello-World/issues/810/labels{/name}',
    comments_url: 'https://api.github.com/repos/octocat/Hello-World/issues/810/comments',
    events_url: 'https://api.github.com/repos/octocat/Hello-World/issues/810/events',
    html_url: 'https://github.com/octocat/Hello-World/pull/810',
    id: 747843269,
    node_id: 'MDExOlB1bGxSZXF1ZXN0NTI0OTkzMTY0',
    number: 810,
    title: 'Test PR for Codespaces',
    user: {
      login: '2percentsilk',
      id: 3174849,
      node_id: 'MDQ6VXNlcjMxNzQ4NDk=',
      avatar_url: 'https://avatars3.githubusercontent.com/u/3174849?v=4',
      gravatar_id: '',
      url: 'https://api.github.com/users/2percentsilk',
      html_url: 'https://github.com/2percentsilk',
      followers_url: 'https://api.github.com/users/2percentsilk/followers',
      following_url: 'https://api.github.com/users/2percentsilk/following{/other_user}',
      gists_url: 'https://api.github.com/users/2percentsilk/gists{/gist_id}',
      starred_url: 'https://api.github.com/users/2percentsilk/starred{/owner}{/repo}',
      subscriptions_url: 'https://api.github.com/users/2percentsilk/subscriptions',
      organizations_url: 'https://api.github.com/users/2percentsilk/orgs',
      repos_url: 'https://api.github.com/users/2percentsilk/repos',
      events_url: 'https://api.github.com/users/2percentsilk/events{/privacy}',
      received_events_url: 'https://api.github.com/users/2percentsilk/received_events',
      type: 'User',
      site_admin: false
    },
    labels: [],
    state: 'open',
    locked: false,
    assignee: null,
    assignees: [],
    milestone: null,
    comments: 0,
    created_at: '2020-11-20T22:48:47Z',
    updated_at: '2020-11-20T22:48:47Z',
    closed_at: null,
    author_association: 'NONE',
    active_lock_reason: null,
    pull_request: {
      url: 'https://api.github.com/repos/octocat/Hello-World/pulls/810',
      html_url: 'https://github.com/octocat/Hello-World/pull/810',
      diff_url: 'https://github.com/octocat/Hello-World/pull/810.diff',
      patch_url: 'https://github.com/octocat/Hello-World/pull/810.patch'
    },
    body: '',
    performed_via_github_app: null
  },
  {
    url: 'https://api.github.com/repos/octocat/Hello-World/issues/808',
    repository_url: 'https://api.github.com/repos/octocat/Hello-World',
    labels_url: 'https://api.github.com/repos/octocat/Hello-World/issues/808/labels{/name}',
    comments_url: 'https://api.github.com/repos/octocat/Hello-World/issues/808/comments',
    events_url: 'https://api.github.com/repos/octocat/Hello-World/issues/808/events',
    html_url: 'https://github.com/octocat/Hello-World/issues/808',
    id: 744550518,
    node_id: 'MDU6SXNzdWU3NDQ1NTA1MTg=',
    number: 808,
    title: 'Click Here',
    user: {
      login: 'irfaardy',
      id: 49023326,
      node_id: 'MDQ6VXNlcjQ5MDIzMzI2',
      avatar_url: 'https://avatars1.githubusercontent.com/u/49023326?v=4',
      gravatar_id: '',
      url: 'https://api.github.com/users/irfaardy',
      html_url: 'https://github.com/irfaardy',
      followers_url: 'https://api.github.com/users/irfaardy/followers',
      following_url: 'https://api.github.com/users/irfaardy/following{/other_user}',
      gists_url: 'https://api.github.com/users/irfaardy/gists{/gist_id}',
      starred_url: 'https://api.github.com/users/irfaardy/starred{/owner}{/repo}',
      subscriptions_url: 'https://api.github.com/users/irfaardy/subscriptions',
      organizations_url: 'https://api.github.com/users/irfaardy/orgs',
      repos_url: 'https://api.github.com/users/irfaardy/repos',
      events_url: 'https://api.github.com/users/irfaardy/events{/privacy}',
      received_events_url: 'https://api.github.com/users/irfaardy/received_events',
      type: 'User',
      site_admin: false
    },
    labels: [],
    state: 'open',
    locked: false,
    assignee: null,
    assignees: [],
    milestone: null,
    comments: 1,
    created_at: '2020-11-17T09:09:54Z',
    updated_at: '2020-11-23T09:43:57Z',
    closed_at: null,
    author_association: 'NONE',
    active_lock_reason: null,
    body: 'I love you\r\n\r\n----\r\n[Click Here](https://github.com/irfaardy)',
    performed_via_github_app: null
  },
  {
    url: 'https://api.github.com/repos/octocat/Hello-World/issues/576',
    repository_url: 'https://api.github.com/repos/octocat/Hello-World',
    labels_url: 'https://api.github.com/repos/octocat/Hello-World/issues/576/labels{/name}',
    comments_url: 'https://api.github.com/repos/octocat/Hello-World/issues/576/comments',
    events_url: 'https://api.github.com/repos/octocat/Hello-World/issues/576/events',
    html_url: 'https://github.com/octocat/Hello-World/pull/576',
    id: 515476262,
    node_id: 'MDExOlB1bGxSZXF1ZXN0MzM0OTMzMjIy',
    number: 576,
    title: 'Update README',
    user: {
      login: 'NX007KTR',
      id: 41190306,
      node_id: 'MDQ6VXNlcjQxMTkwMzA2',
      avatar_url: 'https://avatars3.githubusercontent.com/u/41190306?v=4',
      gravatar_id: '',
      url: 'https://api.github.com/users/NX007KTR',
      html_url: 'https://github.com/NX007KTR',
      followers_url: 'https://api.github.com/users/NX007KTR/followers',
      following_url: 'https://api.github.com/users/NX007KTR/following{/other_user}',
      gists_url: 'https://api.github.com/users/NX007KTR/gists{/gist_id}',
      starred_url: 'https://api.github.com/users/NX007KTR/starred{/owner}{/repo}',
      subscriptions_url: 'https://api.github.com/users/NX007KTR/subscriptions',
      organizations_url: 'https://api.github.com/users/NX007KTR/orgs',
      repos_url: 'https://api.github.com/users/NX007KTR/repos',
      events_url: 'https://api.github.com/users/NX007KTR/events{/privacy}',
      received_events_url: 'https://api.github.com/users/NX007KTR/received_events',
      type: 'User',
      site_admin: false
    },
    labels: [],
    state: 'open',
    locked: false,
    assignee: null,
    assignees: [],
    milestone: null,
    comments: 1,
    created_at: '2019-10-31T14:26:43Z',
    updated_at: '2020-11-29T05:03:18Z',
    closed_at: null,
    author_association: 'NONE',
    active_lock_reason: null,
    pull_request: {
      url: 'https://api.github.com/repos/octocat/Hello-World/pulls/576',
      html_url: 'https://github.com/octocat/Hello-World/pull/576',
      diff_url: 'https://github.com/octocat/Hello-World/pull/576.diff',
      patch_url: 'https://github.com/octocat/Hello-World/pull/576.patch'
    },
    body: '',
    performed_via_github_app: null
  }
]
```
</div></details>