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のプロジェクトに追加しましょう。
1 2 |
npm i node-fetch npm i proxy-agent |
もちろん、Proxyの無い環境であれば不要なので、ここではnode-fetchだけをインストールすればOKです。
ソースコードとレスポンス
index.js側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
//モジュールを追加する 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という不穏なスレッドが立っています。利用者多いはずなのですが大丈夫かな?)
レスポンスデータ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
{ "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の値だけで十分です。それぞれ祝日名と日付になります。
図:無事に取得出来ました。