GitHub APIを使って、GitHub上の自分のリポジトリの一覧を表示する簡易なウィジェットを作ってみた。

By | 2018年11月25日 , Last update: 2021年3月13日

はじめに

「おすすめログ」の公開を終了する(※2018年11月に終了しました。詳しくはこちらをご参照ください。)とサイドバーがその分すきまが開いてしまうので、別のウィジェットのようなもので埋め合わせる必要があります。

そこで、

「目には目を、APIにはAPIを。」

とか、

「APIをもってAPIを制す。」

というわけで、GitHub APIを使って自分が開発したコードGitHub上の自分のリポジトリの一覧を表示するためのウィジェットを作成することにしました。

スポンサーリンク

まず、設計を行います。

考慮が必要な点。

APIを使う以上は、リクエスト回数に制限がかかることは避けられません。

したがって、「あるページへのアクセスがあるごとにAPIを呼び出して、何らかの情報を取得する。」というような仕様にしてしまうと、万が一そのページが大人気になってしまった場合に、「リクエスト回数の上限に達しました。」的なエラーを返されてしまい、肝心のコンテンツを提供できないという事態になりかねません。

また、APIを呼び出す際のオーバーヘッドもブラウザからのリクエストに対するレスポンスに影響を与える可能性がありますので、ページへのアクセスとAPIの呼び出しを同期させるのは避けたいところです。

これが、仕様です。

前節の考慮を踏まえ、以下の仕様としました。データベースにcache用のテーブルを作っておいて、そこにいったん情報を蓄積するという、いろいろと確実ではありますがちょっとダサい仕様です。

  1. GitHub APIへのアクセスはWebページへのアクセスとは非同期で行う。
  2. GitHub APIから取得したリポジトリについての情報のうち、ウィジェットで必要な項目のみをWordpressが使用しているデータベースに新設するテーブルに格納する。
  3. Webページへのアクセスがあった際には、上記のテーブルから情報を取り出して、ウィジェットを作成する。

サクサクと実装。

仕様が決まったところで、サクサクと実装していきます。

データベースのテーブル作成用のSQL文を作る。

まず、データベースのテーブル作成用のSQL文を作ります。

以下の通りになります。

drop table if exists gitrepo; create table gitrepo ( id int(11) not null auto_increment, name varchar(4096) default null, node_id varchar(40) default null unique, html_url varchar(4096) default null, description varchar(4096) default null, updated_at datetime not null default current_timestamp, pushed_at datetime not null default current_timestamp, created_at datetime not null default current_timestamp, primary key(id) ) ENGINE=InnoDB default charset=utf8mb4;

スポンサーリンク

 
上記のSQL文により、Wordpressのデータベース上に”gitrepo”という名前のテーブルを作成します。

gitrepoテーブルは以下のカラムを持ちます。なお、当面の間使用しないものも含まれています。なお、id以外のカラムはすべてAPIから取得されたものを格納します。

  • id: WordPressのデータベースで割り当てるID。
  • name: リポジトリ名。
  • node_id: ノードID。
  • html_url: リポジトリのURL。
  • description: リポジトリの説明。
  • updated_at: リポジトリの最終更新日時。
  • pushed_at: リポジトリに最後にpushが行われた日時。
  • created_at: リポジトリが作成された日時。

GitHub APIへのアクセス用のPython3のプログラム。

スポンサーリンク

テーブルの定義ができたら、GitHub APIへアクセスし、データベースへの書き込み用のSQL文を標準出力に出力するPython3のプログラムを書きます。

以下のような感じになります。ISO8601形式からPython3のdatetimeクラスのインスタンスへの変換はこちらのサイト様の記事を参考にさせていただいております。

また、24行目のURLに”pandanote-info”とハードコーディングされていますが、他のリポジトリに対して使用する場合には修正が必要です。

#!/usr/bin/env python3
import json
import pytz
from datetime import datetime
import urllib.request
def iso_to_jstdt(iso_str):
dt = None
try:
dt = datetime.strptime(iso_str, '%Y-%m-%dT%H:%M:%SZ')
dt = pytz.utc.localize(dt).astimezone(pytz.timezone("Asia/Tokyo"))
except ValueError:
try:
dt = datetime.strptime(iso_str, '%Y-%m-%dT%H:%M:%S')
dt = dt.astimezone(pytz.timezone("Asia/Tokyo"))
except ValueError:
pass
return dt
def jstdt_to_timestamp(dt):
return dt.strftime('%Y-%m-%d %H:%M:%S')
url='https://api.github.com/users/pandanote-info/repos'
request = urllib.request.Request(url)
try:
with urllib.request.urlopen(request) as response:
body = response.read()
except urllib.error.HTTPError as err:
print(err.code)
except urllib.error.URLError as err:
print(err.reason)
repos = json.loads(body)
for repo in repos:
print("insert into gitrepo(name,node_id,html_url,description,updated_at,pushed_at,created_at) values('{0:s}','{1:s}','{2:s}','{3:s}','{4:s}','{5:s}','{6:s}') on duplicate key update name=values(name),html_url=values(html_url),description=values(description),updated_at=values(updated_at),pushed_at=values(pushed_at),created_at=values(created_at);".format(repo["name"],repo["node_id"],repo["html_url"],repo["description"],jstdt_to_timestamp(iso_to_jstdt(repo["updated_at"])),jstdt_to_timestamp(iso_to_jstdt(repo["pushed_at"])),jstdt_to_timestamp(iso_to_jstdt(repo["created_at"]))))

データ書き込み/更新用のSQL文ではINSERT … ON DUPLICATE KEY UPDATE文を使っています。

上記のプログラムで作成したSQL文をmysqlコマンドを使って流し込みます。SQL文の実行前にSQL文の内容を確認した方が良いと思ったこと(間違いがあると、後で修正するのが大変ですからね。)と、GitHubのリポジトリなんてそう滅多に大量生産するものではないので、この部分は当面の間、手動で実行することとしました。

ウィジェットを表示するためのショートコードを書く。

最後にウィジェットを表示するためのWordpress用のショートコードを書きます。


スポンサーリンク

以下のようなコードになります。実装及び仕様上の特徴は以下の通りです。

  1. データベースへのアクセスはwpdbインスタンスを使って行います。
  2. サイドバーに表示することが前提のユーザインタフェースとしています。

また、実際に本Webサイトで使用しているコードではGitHub Pages用のURL及びリポジトリ名を書き換えるためのコードが含まれていますが、その部分は削除しています。

<?php
function create_githubrepo_widget() {
global $wpdb;
$sql = 'select name, html_url, description from gitrepo';
wpdb->get_results($sql, ARRAY_A);
$snippet = '<div style="width:305px;margin: 0 auto;">';
foreach(row) {
row["html_url"];
row["name"];
if ($name == "pandanote-info.github.io") {
$url = "https://sidestory.pandanote.info/";
$name = "sidestory.pandanote.info";
}
url.'"><span style="color:#1E3E8A;font-weight:bold;font-size:130%;">'.row["description"].'<hr/>';
}
return $snippet . '</div><div class="clear"></div>';
}
add_shortcode('create-githubrepo-widget','create_githubrepo_widget');
?>

さらに、functions.phpの末尾に以下の行を追加して、上記のコードを読み込んでいます。

require_once( get_template_directory() . ‘/githubrepo_widget.php’);

 

ウィジェットの表示例。

ウィジェットの表示例は以下のようになります。シンプルなデザインとしています。

コードをGitHubに置きました。

リポジトリはこちらです。

動作の保証はできませんが、参考にしていただけると幸いです。

まとめ

というわけで、やっつけ仕事感満載ではありますが、GitHub APIを使った簡易なウィジェットを作ってみました。

この記事で書いたような使い方だと認証なしでGitHub APIが使える(この記事を最初に書いた時点(2018年11月)の情報です。)ので、実装も楽チンです。

実は、本Webサイトはサイドバーの広告がクリックされることが(一般的なアフィリエイト方面のサイト様で言われているよりも、)比較的多いと感じています。クリックされることが多いのは本文の広告がクリックされていないということよりも、サイドバーにも独自なコンテンツを掲載しているからであると本サイトの管理人たるpandaは固く信じて疑わないので、今後もサイドバーに掲載できるコンテンツがあれば積極的に掲載したいと考えています。🐼

この記事は以上です。

References / 参考文献