勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

GASで祝日一覧(年月日と祝日名)データをJSON出力するAPIを作成

  Google Apps Script Google

PHPのシステム案件で祝日を取得し、処理を行う箇所があった。GoogleカレンダーのAPIに接続してどうこうしようかと考えたが、カレンダーAPIを使ったことが無いのと、GoogleMapsAPIみたいにAPIキーが必須だった場合、クライアント様にキーを発行いただく必要がありその辺りが面倒だった。結局のところ他所様のAPIを使用して実装したが、よくよく考えればこういった時こそGoogle Apps Scriptの出番じゃないかと思った。以下に祝日APIの作成方法をメモ。

 

やりたいこと

今年と来年の祝日一覧(年月日と祝日名)をJSON出力するAPIを作成したい。

APIリクエスト時にGoogleログイン認証は不要だが、GoogleMapsAPIのAPIキーのようにGETパラメータをつけることで認証させたい。もちろんキーが無い場合はデータを返さない。

法改正等による祝日の変更を考慮し、1日に1回Googleカレンダーから祝日データを引っ張ってきてスプレッドシートに保存・更新したい。

 

GAS側の作業

必要な作業はプログラムの作成、トリガーの設定、デプロイになる。

プログラムの作成

//スプレッドシートに祝日データを書き込む関数
function setHoliday(){

	//開始年月日と終了年月日の指定
	const now = new Date();
	const start = now.getFullYear() + '-01-01';
	const end = (now.getFullYear() + 1) + '-12-31';

	//Googleカレンダーから祝日取得
	const calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com').getEvents(new Date(start), new Date(end));

	//祝日データを整形して配列に格納
	const result = [];
	for( var i = 0; i < calendar.length; i++ ){
		result[i] = [
			Utilities.formatDate(calendar[i].getStartTime(), 'JST', 'yyyy-MM-dd'), 
			calendar[i].getTitle()
		];
	}

	//正常にデータが取得できた場合、スプレッドシートに書き込み
	if( result.length ){

		//スプレッドシートの読み込み
		const sheet = SpreadsheetApp.getActiveSpreadsheet();

		//シートを指定
		const holidaySheet = sheet.getSheetByName('holiday');

		//シートにまとめて書き込み
		holidaySheet.getRange(1, 1, result.length, result[0].length).setValues(result);
	}
}

//祝日データをJSON出力
function getHoliday(){

	//スプレッドシートの読み込み
	const sheet = SpreadsheetApp.getActiveSpreadsheet();

	//シートを指定
	const holidaySheet = sheet.getSheetByName('holiday');

	//シートのデータを取得
	const holidaySheetVal = holidaySheet.getDataRange().getValues();

	//年月日の整形
	for( let i = 0; i < holidaySheetVal.length; i++ ){
		holidaySheetVal[i][0] = Utilities.formatDate(holidaySheetVal[i][0], 'JST', 'yyyy-MM-dd');
	}

	//データをJSON化
	const payload = JSON.stringify(holidaySheetVal);

	//Textoutputオブジェクトを生成
	const output = ContentService.createTextOutput();

	//Mime TypeをJSONに設定
	output.setMimeType(ContentService.MimeType.JSON);

	//データ出力
	output.setContent(payload);

	return output;
}

//API呼び出し時に動作する関数
function doGet(e){
	const key = e.parameter.key;
	const apiKey = 'xxxxxxxxxxxxxxxx';

	if( key != apiKey ){
		return ContentService.createTextOutput('アクセスできませんでした。');
	}

	return getHoliday();
}

カレンダーデータ取得部分のエラー

「CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com')」の部分が動かず、以下のようなエラーメッセージが表示された。

TypeError: Cannot find function getEvents in object

GASで使うGoogleアカウントが最近取得したばかりでGoogleカレンダーを作成していなかった。Googleカレンダーを作成することで上記エラーが改善された。

他には以下のような場合もある模様。

https://teratail.com/questions/189134

http://syasuda.com/d/blog/2016/11/googleid.html

API呼び出し時

「const apiKey = 'xxxxxxxxxxxxxxxx';」の部分は適宜変更する。

年月日のフォーマット

「Utilities.formatDate(年月日データ, 'JST', 'yyyy-MM-dd')」でフォーマットする。フォーマット指定文字は以下の通り。

https://sites.google.com/site/gasgaidobukku/utilities/formatdate

APIリクエスト時のGETパラメータ取得

APIリクエスト時はdoGet関数が動作する。GETパラメータを取得したい場合は「e.parameter.パラメータのキー」で取得できる。リファレンスは以下の通り。

https://developers.google.com/apps-script/guides/web

トリガーの設定

setHoliday関数が1日1回動作するようトリガーを設定しておく。

デプロイ

「右上のデプロイボタン→新しいデプロイ」に進み「説明」は適当、「種類の選択」はウェブアプリ、「次のユーザーとしての実行」を自分、「アクセスできるユーザー」を全員で設定する。何故か初回デプロイ時は「アクセスできるユーザー」に全員の選択肢が無かった。「デプロイを管理→アーカイブ」で削除すると2回目以降からは全員を選択できた。

デプロイが完了するとURLが発行されるのでブラウザから開いてみると正常に動作した。尚、APIキーをGETパラメータとして付与するのを忘れないよう注意する。

 

API利用時の注意

GASの利用制限や上限にひっかからないよう、API利用時はデータを取得後にファイル化するのが良さそう。データとは別にファイルの有効期限を設定しておき、有効期限が切れていれば再度APIからデータを取得するような形が望ましいかと思われる。ざっくりとだけど以下のような形。

//祝日APIにリクエスト
$api = file_get_contents('http://api.com/');
$holiday = json_decode($api, true);

//JSONファイル用の制限時間
$holiday['limit'] = date('Y-m-d H:i:s', strtotime('+1 day'));

//JSONファイル上書き保存
file_put_contents('./holiday.json', json_encode($holiday));

 

所感

GASはイマイチ業務での使いどころが思いつかないなぁ、とか考えながら勉強していたがやっと役に立ちそうなケースが出てきて嬉しい。

 - Google Apps Script Google

  関連記事

GASで特定サイトをスクレイピングし、画像をGoogleドライブに保存

Google Apps Scriptで特定のサイトにスクレイピングし、画像が掲載 ...

GASでNintendo Storeをチェックし指定したソフトが〇円以下の際に通知する方法

Google Apps Scriptを利用してNintendo Storeをスク ...

GASで特定サイトにログインした後にスクレイピングを行う方法

Google Apps Scriptの勉強として特定サイトにログインし、その後に ...

GASとGmailを連携させて受信メール検索及びメール送信

Google Apps ScriptとGmailを連携させてみたい。「未読かつ特 ...

GASで「小説家になろう」サイトの更新通知をLINEに送る方法

Google Apps Scriptの勉強として「小説家になろう」サイトの特定小 ...