WebAPI A3

WebAPIが提供する機能


ベアボーンサーバ(pill-reminder.js)からのリクエストに応じてGoogleカレンダーに登録されている服薬予定を返却する機能を提供するWebAPI。リクエストに含まれるパラメタの値に応じて、当日の全予定(朝、昼、夕、就寝前など)を返却する機能と、指定したidの予定のみ返却する機能がある。

構築環境


GAS (Google Apps Script) を利用して開発。
doGetを使ったGETメソッドによるWebAPIの提供

インターフェース


当日の全件予定のリクエスト


入力データ(ベアボーンサーバ → Webサービス)

{
  "parameter": {},
  "contextPath": "",
  "contentLength": -1,
  "queryString": "",
  "parameters": {}
}
リスト1.当日の全予定を要求された場合

GETメソッドにおいて何もパラメタを設定しない場合(クエリストリングがない場合)は、当日の全予定をGoogleカレンダーから取得して返却する。

出力データ(Webサービス → ベアボーンサーバ)

{
 "drug_notifies": [
  {
   "title": "朝の食後の薬(未)",
   "description": "クラビット細粒10% 100mg(レボフロキサシンとして) 3g",
   "id": "4unup4q0nvecekung915hhaq68@google.com",
   "location": "0",
   "startTime": "2019-10-11T08:36:00.000Z",
   "endTime": "2019-10-11T08:39:00.000Z",
   "color": "11"
  },
  {
   "title": "夜の食後の薬(未)",
   "description": "クラビット細粒10% 100mg(レボフロキサシンとして) 3g",
   "id": "0s826bi4tecvamgadmklj9faod@google.com",
   "location": "0",
   "startTime": "2019-10-11T10:00:00.000Z",
   "endTime": "2019-10-11T10:03:00.000Z",
   "color": "11"
  },
  {
   "title": "昼の食後の薬(未)",
   "description": "クラビット細粒10% 100mg(レボフロキサシンとして) 3g",
   "id": "2tjms6utgpmqi07nma49v4tt0e@google.com",
   "location": "0",
   "startTime": "2019-10-11T11:00:00.000Z",
   "endTime": "2019-10-11T11:03:00.000Z",
   "color": "11"
  }
 ],
 "num_reminder": "0",
 "taiking_status": "0",
 "status": "0"
}
リスト2.当日の全予定の返却データ


idを指定して予定をリクエスト


入力データ(ベアボーンサーバ → Webサービス)

{
 "parameter": {
  "num_reminder": "1",
  "id": "4unup4q0nvecekung915hhaq68@google.com"
 },
 "contextPath": "",
 "contentLength": -1,
 "queryString": "id=4unup4q0nvecekung915hhaq68@google.com&num_reminder=1",
 "parameters": {
  "num_reminder": [
   "1"
  ],
  "id": [
   "4unup4q0nvecekung915hhaq68@google.com"
  ]
 }
}
リスト3.idを指定して予定を要求された場合

GETメソッドにおいて、クエリストリングに
?id=[服薬予定のイベントid]&num_remind=[催促回数]
と設定した場合は、GASプログラム(doGet()関数)はリスト3に示すJSONデータを受け取るので、その中にあるidを使ってGoogleカレンダーから取得した予定を返却する。

出力データ(Webサービス → ベアボーンサーバ)

{
 "drug_notifies": [
  {
   "title": "夜の食後の薬(応答無)",
   "description": "クラビット細粒10% 100mg(レボフロキサシンとして) 3g",
   "id": "5ihpjn5979l6pt0u8v6molgfvc@google.com",
   "location": "0",
   "startTime": "2019-10-12T22:15:00.000Z",
   "endTime": "2019-10-12T22:20:00.000Z",
   "color": "5"
  }
 ],
 "num_reminder": "11",
 "taiking_status": "0",
 "status": "0"
}
リスト4.idを指定して取得した服薬予定の返却データ


リスト4に示すJSON形式の返却データにおいて、taking_statusには、未服用の場合には"0"が、服用済みの場合は"1"が設定される。

プログラム


当該WebAPIはGETメソッドとして実装するのでdoGet関数を使用する。doGet関数の引数eの中に、リスト1もしくはリスト3に示す入力パラメタがオブジェクト形式で設定される。

function doGet(e) {
  debug(JSON.stringify(e, null, ' '));
  
  // idの有無に応じて呼び出す関数を変える
  if(e.parameter.id) {
    response = getEventsById(e.parameter.id,e.parameter.num_reminder);
  } else {
    response = getEventsForDay();
  }
  
  //イベントをジェイソン形式でとってくる
  var out = ContentService.createTextOutput();
  
  //Mime TypeをJSONに設定
  out.setMimeType(ContentService.MimeType.JSON);
  
  //JSONテキストをセットする
  out.setContent(JSON.stringify(response));
  
  return out;
}
リスト5.エントリーポイント(doGet関数)

まず、入力データの中にid (e.parameter.id) があれば、そのidで指定された特定の服薬予定をリクエストしてきたものとみなしてgetEventById()関数を呼び出す。
一方、idが設定されていない場合は、その日の全予定をリクエストしてきたものとみなしてgetEventForDay()関数を呼び出す。
各々の関数では、要求された予定をGoogleカレンダーから取得して返却する。

 指定したidの予定のみ返却するgetEventById()関数をリスト6に示す。

function getEventsById(id,num_reminder) {
  debug("getEventsById(" + id + "," + num_reminder + ")");
  
  //「の薬」とつくイベントの取得  
  var event = CalendarApp.getEventById(id);
  var pills = [];
 
  //ジェイソン形式にする 
  var pill = {
    "title":event.getTitle(),
    "description":event.getDescription(),
    "id":event.getId(),
    "location":event.getLocation(),
    "startTime":event.getStartTime(),
    "endTime":event.getEndTime(),
    "color":event.getColor()
  };
  //pills(変数)にpillを追加
  pills.push(pill);
 
  var response = {
    "drug_notifies": pills,
    "num_reminder": num_reminder,    // 催促回数
    "taiking_status": event.getTitle().indexOf("(済)") < 0 ? '0' : '1',    // 服用状況 (0:未服用, 1:服用済)
    "status": "0"        // 0=成功, 1:失敗
  }
  
  Logger.log(JSON.stringify(response,null,' '));
  
  // 未服用でかつ催促の回数が5回以上になったらタイトルに「(応答無)」に変更し、色を黄色に変える
  if(response.taiking_status == '0' && num_reminder >= 5){
    result = event.getTitle().indexOf("(");     
    //"("以降の文字を切り取る。
    results = event.getTitle().substr(0,result);
    //タイトルを○○の薬(応答無)に変更する。  
    event.setTitle(results+'(応答無)');
    //色を黄に変更する。
    event.setColor(CalendarApp.EventColor.YELLOW); 
    //LINEにメッセージを送る
    LINE_notify('お薬を飲むように催促しましたが応答がありません。');
  }
  return response;
}

リスト6.getEvebtById()関数

この関数によってリスト4の返却データが生成される。なお、この関数では、催促回数(num_reminder)が5回以上になったら、Googleカレンダーの予定に付けてあるタイトルの「(未)」を「(応答無)」に変更し、なおかつ、色を黄色に変更する。こうして、服用を促すメッセージに応答がなかった場合のGoogleカレンダーに対する変更処理を行っている。さらにこの場合、関数LINE_notify(リスト10)を使ってLINEへ「お薬を飲むように催促しましたが応答がありません。」というメッセージを送る。

リスト7は、その日のすべての服薬予定をGoogleカレンダーから取得して返却する関数getEventForDay()である。

function getEventsForDay() {
  //「の薬」とつくイベントの取得  
  var events = CalendarApp.getDefaultCalendar().getEventsForDay(
    new Date(),
    {search:'の薬'}
  );  
  var pills = [];
  events.forEach(function(event,i,array){
    //ジェイソン形式にする 
    var pill = {
      "title":event.getTitle(),
      "description":event.getDescription(),
      "id":event.getId(),
      "location":event.getLocation(),
      "startTime":event.getStartTime(),
      "endTime":event.getEndTime(),
      "color":event.getColor()
    };
    //pills(配列)にpillを追加
    pills.push(pill);
  });  
 
  var response = {
    "drug_notifies": pills,
    "num_reminder": "0",    // 催促回数
    "taiking_status": "0",    // 服用状況 (0:未服用, 1:服用済)
    "status": "0"        // 0=成功, 1:失敗
  }
  Logger.log(JSON.stringify(response,null,' '));
  return response;
}
リスト7.getEventForDay()関数

getEventForDay()関数では、服薬予定以外の予定を除外するために「の薬」というキーワードを含むイベントのみを検索対象としている。

その他


GASの公開ウェブアプリケーションはLogger.log()関数によるログが取れないのでデバッグ作業が難しい。そこで、Googleドキュメントにログを書き込む関数debug()を準備した。リスト8がそれである。

function debug(meseage){
  var doc = DocumentApp.openById('1cW.............................M9E');
  var body= doc.getBody();
  body.appendParagraph(formatDate(new Date()) + '(A3):' + meseage);
}
リスト8.debug()関数

ここで、ログ出力用のGoogleドキュメント(ファイル名Debug)を作成し、そのIDをDocumentApp.openById()関数の引数に設定する。

ログ出力時に日時を編集するための関数がリスト9に示すformatDate()関数である。

/**
 * 日付をフォーマットする
 * @param  {Date}   date     日付
 * @param  {String} [format] フォーマット
 * @return {String}          フォーマット済み日付
 */
function formatDate(date, format) {
  if (!format) format = 'YYYY-MM-DD hh:mm:ss.SSS';
  format = format.replace(/YYYY/g, date.getFullYear());
  format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
  format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
  format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
  format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
  format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
  if (format.match(/S/g)) {
    var milliSeconds = ('00' + date.getMilliseconds()).slice(-3);
    var length = format.match(/S/g).length;
    for (var i = 0; i < length; i++) format = format.replace(/S/, milliSeconds.substring(i, i + 1));
  }
  return format;
};
リスト9.日時編集関数formatDate

リスト10は、LINE notifyを使ってLINEへメッセージを送る関数である。
//Lineにメッセージを送るファンクション
function LINE_notify(message){
  var token = "5EW..............................Dv4";
  var options =
   {
     "method"  : "post",
     "payload" : "message=" + message,
     "headers" : {"Authorization" : "Bearer "+ token}

   };

   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}
リスト10.LINEへメッセージを送る関数

リスト10のtokenはLINE notifyで発行したトークンである。

0 件のコメント:

コメントを投稿