勉強したことのメモ

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

  関連記事

GoogleスプレッドシートとPHPを連携させデータを取得・追記する方法

GoogleスプレッドシートとPHPプログラムを連携させたいという案件をたまに見 ...

GASで「カクヨム」の更新状況をスクレイピングで取得する

Google Apps Scriptの勉強として「カクヨム」の指定した小説が更新 ...

GASを使って任天堂ホームページ更新情報のRSSを取得する方法

GASを使ってRSSを取得してみたい。今回はニンテンドーホームページ更新情報とい ...

GASとDrive APIを組み合わせて画像やPDFファイルをOCR処理する方法

Googleドライブに保存した画像やPDFファイルをOCR処理し、ファイル内のテ ...

GASを利用してGmailに届いたメール内容をGoogleスプレッドシートに記入する方法

WordPressのContact Form7から送信した内容をGmailで受け ...