@mizumotokのブログ

テクノロジー、投資、書評、映画、筋トレなどについて

GitHub ActionsとGitHub PagesでつくるWeb API(郵便番号検索)

GitHubが値下げと無料の「Free」プランの拡充を発表しました。昨年はCI/CD機能であるGitHub Actionsをリリースしたり、GitHub Pages(静的サイトホスティング)やPackages(パッケージホスティング)、Projects(プロジェクト管理)などがすでにあり、機能がどんどん充実していきます。
アプリケーションを動かすことはまだできないのですが、GitHub Actionsでプログラムを動かせるようになったので、GitHub Pagesと組み合わせれば、簡単なWeb APIもできます。
さっそく郵便番号から住所を返すAPIを作ってみます。

GitHub Actions

GitHubが無料の「Free」プランを拡充

GitHubは2020年4月14日に値下げを行い、無料の「Free」プランを拡充してくれました。
github.blog
個人だけでなく組織でも、無制限のプライベートリポジトリと無制限のコラボレーターが無料で使えるようになったのです。
GitHubは今やgitレポジトリだけでなく、静的サイトのホスティングGitHub Pages)やCI/CD(GitHub Actions)もついていて、進化が止まりませんね。他のgitレポジトリサービスはどんどん差がついてきついんじゃないかと思われます。

Free Plan

  • Unlimited public/private repositories
  • Unlimited collaborators
  • 2,000 Actions minutes/month(Free for public repositories)
  • 500MB of GitHub Packages storage(Free for public repositories)
  • Community Support
https://github.com/pricing

GitHubだけでWeb API

GitHubにはGitHub Pagesという静的サイトのホスティングサービスはありますが、herokuやfirebase、GAEのようなアプリケーションプラットフォーム(PaaS)は用意されていません。
ちょっとしたWeb APIGitHubでつくれるようになるといいなと思います。
Web APIはデータベースから(検索して)データを返すだけなので、gitレポジトリをデータベース代わりにして、APIGitHub PagesでつくられるURLから提供すれば簡単なAPIを作ることはできます。
そして、今、GitHubにはGitHub Actionsがあります。GitHub Actionsはリクエストに応じた実行こそできませんが、いろいろなタイミング(トリガー)でさまざまなプログラムを実行することができます。そのタイミングでデータを更新する(データを取得してレポジトリにコミット/プッシュ)くらいはできてしまいます。これを利用して、最新のデータを維持したWeb APIを作ってみましょう。

郵便番号検索API

郵便番号から住所を表示するというよくあるアレです。
 ↓
mizumotok.github.io

〒100-0001は皇居がある住所(東京都千代田区千代田)の郵便番号です。

/api/100/0001.json

こんなパスで、返すようにしてみます。
api/100/0001.jsonファイルをGitHub Pagesで表示できるところに置くだけです。
郵便番号データは郵便局のウェブサイトからCSV形式でダウンロードできます。このデータをGitHub Actionsで定期的にダウンロードして、json形式に変換して、然るべき場所に保存して、レポジトリにプッシュすればいいわけです。

GitHub Pages

GitHub Pagesは「gh-pages」ブランチ、「master」ブランチ、または「master」ブランチの「docs」ディレクトリのいずれかに静的コンテンツをおくことで、表示することができます。
help.github.com

今回は「master」ブランチ上でデータ作成プログラムをつくって、そこのdocsディレクトリにjsonデータを保存するようにしてみました。
GitHub Pagesはトップページにindex.htmlがないとGitHub Pagesとして認識されないようなので、index.htmlは作っておく必要があります。
せっかくGitHub Pagesをつくるので、Jekyllという静的サイトジェネレータを使ってつくると、それっぽいトップページがちゃちゃっとできます。
help.github.com
もちろんJelyllなしでindex.htmlを作るのもOK。

docsディレクトリはこんな感じになります。
zipcode/docs at master · mizumotok/zipcode · GitHub

郵便番号データ作成プログラム

api/100/0001.jsonのようなファイルを郵便番号の数(全国12万件)だけつくります。

処理の流れ

  1. 郵便局のウェブサイトからファイルをダウンロード
  2. zip形式なので、zipファイルの中からファイルを取り出す
  3. 文字コードはshift-jisなので、utf-8に変換
  4. CSVをパース
  5. 1行ずつjsonに変換してファイルに保存

という流れになります。

データをダウンロードするプログラム

export default async function updateJsonData() {
  const res = await fetch('https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip');
  const buffer = await res.buffer();
  const zip  = await JSZip.loadAsync(buffer);
  const fileName = Object.keys(zip.files)[0];
  const converterStream = iconv.decodeStream('shift_jis');
  zip.file(fileName).nodeStream().pipe(converterStream)
    .pipe(csv({ headers: false }))
    .on('data', (data) => createFile(data));
}

ファイルを保存するプログラム

function createFile(data: string[]) {
  try {
    const dir = data[2].slice(0, 3);
    const file = data[2].slice(3);
    if (dir.length !== 3 || file.length !== 4) {
      console.log(`unknown postal code: ${data[2]}`);
      return;
    }
    fs.mkdirSync(`docs/api/${dir}`, { recursive: true });
    fs.writeFileSync(
      `docs/api/${dir}/${file}.json`,
      JSON.stringify({
        local_government_code: data[0],
        zip_code: data[2],
        address: [data[6], data[7], data[8]],
        address_kana: [data[3], data[4], data[5]]
      }),
    );
  } catch (err) {
    console.log(err);
  }
}

ソースコード全体はこちらにおいてあります。

GitHub Actions

郵便番号データ作成プログラムをGitHub Actions上で実行させます。

GitHub Actionsをトリガーするイベント

GitHub Actionsをトリガーするイベントは3つあります。
今回はデータの更新は頻繁には必要ないので、1ヶ月に1回程度スケジュールイベントを発生させれば十分でしょう。

webhookイベント
CI/CDでよく使われる、プッシュやプルリクエストで発生するイベントです。
developer.github.com

スケジュールしたイベント
特定の時刻に起動する、いわゆるcronです。記述もcronライクです。

# 15分ごとに実行する例
on:
  schedule:
    - cron:  '*/15 * * * *'

外部イベント
GitHub API を使って、repository_dispatchと呼ばれる webhook イベントをトリガーできます。GitHub外部から起動した場合に使います。

GitHub Actionsのつくりかた

.github/workflowsに、ワークフローのため .yml または .yaml ファイルを追加します。

仮想環境の準備
仮想環境にはUbuntuWindowsMacOSがサポートされています。

仮想環境 YAMLのワークフローラベル
Windows Server 2019 windows-latest or windows-2019
Ubuntu 18.04 ubuntu-latestまたはubuntu-18.04
Ubuntu 16.04 ubuntu-16.04
macOS Catalina 10.15 macos-latest or macos-10.15

郵便番号データ作成プログラムはTypescriptで書いたので、Node.jsが実行できればよく、無難にUbuntu 18.04にしておきます。

実行するアクション
仮想環境を指定したら、アクション(タスク)を実行順に記述します。
アクションは自分でプログラムを書いて、runコマンドで実行することができますが、GitHub Marketplaceで多くのアクションが公開されていて、それらを利用することもできます。

以下の順にアクションをつくれば完成です。

  1. レポジトリからチェックアウト(actions/checkout)
  2. Node.js環境の設定(actions/setup-node)
  3. npmパッケージのインストール(runコマンド)
  4. 郵便番号データ作成プログラムの実行(runコマンド)
  5. 作成されたデータをコミット(runコマンド)
  6. レポジトリにプッシュ(ad-m/github-push-action)

作成したワークフローファイル

name: update ZIP Code
on:
  schedule:
    - cron: '5 20 7 * *'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.x'
    - run: yarn install
    - name: Update ZIP Code
      run: yarn main
    - name: Commit files
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git add ./docs/api/
        git commit -m "Update data `date +%Y-%m-%d`" -a
    - name: Push changes
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}

APIの確認

GitHub Actionsでデータが作成され、GitHub Pagesでデータが公開されました。これで郵便番号検索APIの完成です。

ターミナル上から試してみると

% curl https://mizumotok.github.io/zipcode/api/100/0001.json

{"local_government_code":"13101","zip_code":"1000001","address":["東京都","千代田区","千代田"],"address_kana":["トウキョウト","チヨダク","チヨダ"]}

ちゃんと返ってきます。
Good Job!

まとめ

  • GitHub Pagesは特定の場所にファイルを置くだけでウェブサイトとして公開できる
  • GitHub Pagesにjsonファイルやxmlファイルを置けば、Web APIライクになる
  • GitHub Actionsでデータの自動更新ができる
  • 郵便番号検索APIGitHub PagesとGitHub Actionsだけでできた

mizumotok.github.io

GitHub実践入門 ~Pull Requestによる開発の変革 (WEB+DB PRESS plus)

GitHub実践入門 ~Pull Requestによる開発の変革 (WEB+DB PRESS plus)

  • 作者:大塚 弘記
  • 発売日: 2014/03/20
  • メディア: 単行本(ソフトカバー)