ElectronでGoogleカレンダーの日本の祝日を取得する
とあるアプリで、祝日判定をする為に祝日データが必要になったのですが、Googleには公開カレンダーとして日本の祝日というものが用意されています。このデータを取得してデータベースに格納しておけば、手動で祝日登録を行う必要がなくなるので便利です。
ということで、このデータをElectron(Node.js)で取得し、SQLiteのデータベースに格納してみようと思います。
また、今回はいい加減Deprecatedになったrequestモジュールを卒業し、node-fetchモジュールで社内Proxy超えを設定して取得を試みます・
リンク
事前準備
API Keyを取得する
Googleカレンダーにアクセスする為には、Cloud ConsoleよりAPI Keyを生成して取得する必要があります。以下の手順で取得をしておきましょう。予めプロジェクトは作っておいてください。
- Google Cloud Consoleにログインする
- サイドバーを開き、「APIとサービス」を開く
- 上部にある「APIとサービスの有効化」をクリックする
- calendarで検索し、Google Calendar APIをクリックし、有効化をクリックする
- そのまま認証情報を作成するのではなく、一旦APIとサービスに戻り、認証情報をクリックする
- 上部にある「認証情報を作成」をクリックする
- APIキーをクリックする
- すぐにAPIキーが生成されるので、控えておく。
- キーを制限をクリックする
- 今回はAPIの制限にて、キーを制限をクリックし、Google Calendar APIでだけ利用できるようにします。
- 最後に保存するで完了です。
図:APIキーを生成する画面
モジュールを追加する
旧来のrequestモジュールに変わって、node-fetchモジュールを追加します。しかし、node-fetch自身はProxyに対応していないので、追加でさらにproxy-agentモジュールも追加します。ターミナルから以下のモジュールをElectronのプロジェクトに追加しましょう。
npm i node-fetch npm i proxy-agent
もちろん、Proxyの無い環境であれば不要なので、ここではnode-fetchだけをインストールすればOKです。
ソースコードとレスポンス
index.js側コード
//モジュールを追加する
const fetch = require('node-fetch');
var ProxyAgent = require('proxy-agent');
//Google Calendar関係
var apikey = "ここにAPIキーを入力する";
var calid = "ja.japanese#holiday@group.v.calendar.google.com";
var apiurl = "https://www.googleapis.com/calendar/v3/calendars/";
//Proxy URLを指定する
var agent = new ProxyAgent("http://hogehoge.com:8080");
//Googleカレンダーの日本の祝日データを取得する
ipcMain.on('getholiday', function( event ){
//日付の指定
var startday = "2021-01-01";
var endday = "2021-12-31";
//リクエストURLを構築する
var requrl = apiurl + encodeURIComponent(calid) + "/events?key=" + apikey + "&timeMin=" + startday + "T00:00:00.000Z" + "&timeMax=" + endday + "T23:59:59.000Z";
var options = {
method: 'GET',
agent: agent,
headers: { 'Content-Type': 'application/json' },
}
//ステータスコード用
var status
fetch(requrl, options)
.then((res) => {
//ステータスコードを取得
status = res.status;
//body部分を取得
return res.json()
})
.then((jsonData) => {
if(status == 200){
//レコードを取得
var record = jsonData.items;
//取得した祝日情報をSQLiteに追加する
var query = "DELETE FROM holiday_public";
sqlitedelete(query,function (ret){
if(ret == "NG"){
event.sender.send("closeman");
return done();
}
async.eachSeries(record,function(rec,next){
//西暦、月の取得
var tempdate = new Date(rec.start.date);
var seireki = tempdate.getFullYear();
var monthman = tempdate.getMonth() + 1;
var fulldate = getdateman(tempdate);
//クエリを構築
query = "insert into holiday_public (seireki,month,hdate,hname) values (?,?,?,?);"
var values = [seireki,monthman,fulldate,rec.summary];
sqliteinsert(query,values,"holiday_public",function (ret){
if(ret[0] == "NG"){
event.sender.send("error");
return done();
}
//次の処理へ
next();
return;
});
},function(err){
//エラートラップ
if(err){
//メッセージを返して処理を中断
event.sender.send('message', err);
return;
}
//完了通知
event.sender.send('holigetend','祝日の取得が完了しました。');
});
})
}else{
event.sender.send('message', status + "エラー:\n" + jsonData.error.message);
}
})
.catch((err) => {
//エラーメッセージ
event.sender.send('message', status + "エラー:\n" + err);
return;
});
});
- Google CalendarのIDはja.japanese#holiday@group.v.calendar.google.comで、リクエストURLに指定する場合はencodeURIComponentでURLエンコードする必要があります。
- startdayとenddayで日付の範囲を指定しますが、Google Calendarの場合、2年後以降の祝日データは入っていないので注意。
- node-fetchでproxyを透過するには、optionsの中のagentにて指定する必要があります。投稿を表示
- レスポンスはres.json()で取得され、これはBody部分のデータが入っています。
- ステータスはres.statusで取得し判定することが可能です。
- sqlitedeleteとsqliteinsertは自前で用意したSQLiteのデータ削除とデータ追加の為の関数です。
- async.eachSeriesにて1レコードずつ追加しています。
- node-fetch以外にaxiosというリクエストモジュールがあるのですが、自分の環境ではどう頑張ってもproxy関係で躓いてNGだったのでスルーしました。(2021/08/04 - なんかProject Deadという不穏なスレッドが立っています。利用者多いはずなのですが大丈夫かな?)
レスポンスデータ
{
"kind": "calendar#events",
"etag": "\"p32br1nf4k31v20g\"",
"summary": "日本の祝日",
"updated": "2021-06-30T16:26:03.000Z",
"timeZone": "UTC",
"accessRole": "reader",
"defaultReminders": [],
"nextSyncToken": "CMD54u3iv_ECEAAYASC2qIy2AQ==",
"items": [
{
"kind": "calendar#event",
"etag": "\"3235834125780000\"",
"id": "20210101_huquf92av88tta92reljcibi1s",
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=MjAyMTAxMDFfaHVxdWY5MmF2ODh0dGE5MnJlbGpjaWJpMXMgamEuamFwYW5lc2UjaG9saWRheUB2",
"created": "2021-04-08T21:24:22.000Z",
"updated": "2021-04-08T21:24:22.890Z",
"summary": "元日",
"creator": {
"email": "ja.japanese#holiday@group.v.calendar.google.com",
"displayName": "日本の祝日",
"self": true
},
"organizer": {
"email": "ja.japanese#holiday@group.v.calendar.google.com",
"displayName": "日本の祝日",
"self": true
},
"start": {
"date": "2021-01-01"
},
"end": {
"date": "2021-01-02"
},
"transparency": "transparent",
"visibility": "public",
"iCalUID": "20210101_huquf92av88tta92reljcibi1s@google.com",
"sequence": 0,
"eventType": "default"
}
]
}
- itemsの中に複数の祝日データが入っています。
- res.json()で取得する中身になります
- 通常は、itemsのsummaryとstartのdateの値だけで十分です。それぞれ祝日名と日付になります。
図:無事に取得出来ました。



