4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TechCommitAdvent Calendar 2021

Day 16

【GitHub】octkitのREST APIをTypeScriptで使ってみた

Last updated at Posted at 2021-12-15

はじめに

TechCommit Advent Calendar 2021 16日目を担当させていただきます、うらさくと申します!よろしくお願いします。

今回会社でGitHubのOrganizationユーザ管理をGitHub上でやっていこうぜということで、いろいろGitHubのAPIに触れていたのですが、TypeScript(Javascript)で使用されている記事が少なく、少し苦労したところがあるので、octkitの種類から基本的なoctkitの使い方まで簡単にまとめてみました

これらを使うと、UIを使わずにユーザの登録や削除ができますし、ソースコードと一緒にユーザ一覧表を管理することで半自動でユーザの管理をすることができます

GitHubAPI興味あったけど使ったことない方や、GitHubのユーザ管理に悩まれている方のご参考になれば幸いです

octkitとは

GitHub公式のGitHub APIのラッパーです

今回説明するNode.js版の他に、Ruby、.Net等で使用することができます

APIの種類

レポジトリを見ていただくとわかるように、単にoctkitといっても結構種類があります

jsだけで見ても

  • octkit.js
  • rest.js
  • request.js
  • endpoint.js
  • webhook.js
  • adtions.js

などなど

全部説明するのはきりがない(正直私もほとんど知らない^^;)ので、今回は私が使用した、rest.jsについて説明したいと思います

@octkit/rest

@octkit/requestとの違い

javaScript(TypeScript)からGitHubのAPIを叩く場合は、rest.jsとrequest.jsのどちらかになると思います

違いを軽く説明しますと、request.jsは実施にAPIを叩くところを担当しているライブラリで、rest.jsはrequest.jsに認証やフック、ページネーションなどの便利機能を付与した最終的なAPIクライアントです

request.jsをそのまま使ってAPIを叩くことも可能ではありますが、rest.jsの便利機能を捨ててまで使うメリットはあまりないと思いますので、ここからいくつかrest.jsの使い方を説明していきます

用途と使い方

導入とインポート

まずはいつものようにnpm installを実行します

npm install @octokit/rest @octokit/request-error --save

@octokit/request-errorについて

後ろの@octokit/request-errorってなに?と思われた方がいらっしゃると思いますが、これは@octokit/requestのエラーハンドリングで使用しているGitHub独自のエラークラスです。

API実行時に発生したExceptionは、RequestError型としてthrowされます

ですので、クライアント側でcatchするためには、このクラスも同時に使用する必要があります

こちらに関しても使用例のところで軽く触れていきます

用途と使い方

今回はOrganization周りで使うことが多かったので、いくつか紹介させていただきます

Organizationにユーザを招待する

async function sendInvitation(userId: number, teamIds?: number[]): Promise<number | RequestError> {
  const params = {
    org: OWNER,
    invitee_id: userId,
    team_ids: teamIds,
  }

  try {
    const response = await octokit.request('POST /orgs/{org}/invitations', params)
    return response.status
  } catch (e) {
    console.warn(`[WARN] ${e}`)
    const error = e as RequestError
    return error
  }
}

パラメータのうち、org(Organization名)とinvitee_id(招待するユーザID)は必須項目です。
team_idsは招待時にチームを指定するときのみ記載します。(Array形式)

上記の通り、エラーはRequestErrorという独自の型で帰ってくるので、catchしたエラーはキャストしてからreturnします

インターネットアクセスしますので、async/awaitを使用しています

async function main(): Promise<void> {
  for (const member of members) {
      const inviteResponseStatus = await github.sendInvitation(userId, teamIds)
      if (inviteResponseStatus instanceof RequestError) {
        console.error(`[ERROR] Invitation ${member.username} is failed.`)
      } else {
        console.log(`[INFO] Success. Invitation ${member.username} is succeed.`)
      }
    }
  }

呼び出し先で返り値で分岐させることで、複数人招待する際に一人が入力ミスなどでエラーになっても、ログを出して止めずに次の処理へ進ませることができます

ユーザ名からユーザIDを取得

async function getUserIdFromUserName(username: string): Promise<number | RequestError> {
  try {
    const response = await octokit.request('GET /users/{username}', { username: username })
    return response.data.id as number
  } catch (e) {
    console.warn(`[WARN] ${e}`)
    const error = e as RequestError
    return error
  }
}

ユーザIDはUI上から確認することができないので、APIから取得する必要があります

チーム名からチームIDを取得

export async function getTeamIds(teams: string[]): Promise<number[]> {
  const teamIdsList: number[] = []
  for (const team of teams!) {
    const params = {
      org: OWNER,
      team_slug: team,
    }

    try {
      const response = await octokit.request('GET /orgs/{org}/teams/{team_slug}', params)
      teamIdsList.push(response.data.id)
    } catch (e) {
      console.error(`[Error] ${e}`)
      throw new Error(`[Error] Teams ${team} doesn't exist. Please check this team name.`)
    }
  }
  return teamIdsList
}

チームIDも同様です。こちらは配列としてreturnしています

現在Organizationに登録されているユーザを取得する

async function getOrgMembers() {
  const response = await octokit.paginate('GET /orgs/{org}/members', { org: OWNER })
  const memberList = response.map((element) => {
    return { username: element.login }
  })
  return memberList
}

すでに登録されているユーザは上記のように取得できます

ユーザ名一覧のMapをreturnしています

ユーザ名はusernameではなく、loginで取得できる点に注意です

Pagenationについて

リスト系のAPIでは、per_pageオプションで一度に取得する情報数を指定できますが、上限があり一度に最大100件までの情報しか取得できません。これは、GitHub REST APIの制約なので、このようなケースでは本来ならば複数回に分けてリクエストする必要がありますが、rest.jsではPagenationという便利な仕組みを使うことができます。

まとめ

個人での使用に限ればあまり使う機会はないかもしれませんが、Organizationで使用されている方はこれらを使うことでユーザ管理をGitHub上で完結することができます

例えば、、
ユーザ一覧CSV+スクリプトのActionsファイルのGitHubレポジトリ作成

ユーザ一覧CSVに登録したいユーザを追加してPull Request作成

管理者がPRを確認して問題なければマージ

マージ時にActionsからOrganizationへのInviteAPIを叩いてユーザを招待
などでしょうか?

こうすることでわざわざ「登録お願いします」や「登録しました」などのやり取りが不要になるだけでなく、APIを駆使してユーザの上限をチェックしたり、複数のOrganizationを管理する際にも役に立つと思います

他にもいろいろなAPIがあり、使い方は無限大なので、皆さんも色々試してみて、良いGitHubライフをお過ごしください!

ご覧頂きありがとうございました

参考

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?