今回は、Google Apps Scriptの制限を回避して「REST APIっぽいもの」を作る方法について共有していきます。
使用する技術
使用する技術に関しては「Google Apps Script(通称:GAS)」です。GASに関しては、前回の記事で書いているので共有しておきます(Google Apps Script 簡易API編 初心者向け)。GASでは、Googleのサービスとの親和性が高く、メールを出したりGoogle Driveを操作したりと様々なことができます。
今回は、GASで「REST APIっぽいもの」を作るところまでしかやらないので、GAS単体を扱います。GASとGoogle Sheetの連携は先ほど紹介した記事で取り扱っているので気になれば読んでみてください。
GASでの制限
タイトルにも含まれていますが、「REST APIっぽいもの」という問題の根源について話していきます。これは、GASの制限事項に深く関係します。上の図にも書いていますが、大きく3つの制限事項があります。
- 払いだされるURLが1つ ディレクトリでの振り分け不可
- responseのカスタマイズ性が悪い(というか不可能)
- GETとPOSTのHTTPメソッドしか受け取れない
この時点で、「REST API」を構築することが難しいです。REST APIについてはこちらで書いていますので、興味があったら読んでみてください。わかる方はこのまま進みましょう。
responseのカスタマイズ性に関しては、調べた結果ですがステータスコードに関しては固定の200番しか返答することができません。これは調べに調べまわった結果です。初めてGoogle Isuueというものを見ましたが、「これは9年前の記事でおそらく対応されませんね」という文言を見つけて調べるのをやめました(元リンク)。
REST APIを構築するためにはPUTとDELETEの2つが使用したいのですが、GETとPOSTしか受け取ることができないのでこれも障壁の大きな障壁の1つとなっているわけですね。
3つの大きな障壁がある一方で、JSONファイルのやり取りはできるので簡易的なAPIなら問題なく作ることができるわけです。「REST APIっぽいもの」を作るために3つの障壁を何とか回避していこうと思います。それでは、実際に回避する方法について解説していきます。
REST APIっぽいものの構築
さて、実際に「REST API」っぽいものを作るための手順について紹介します。今回の手法を一言で表すならば「すべてのデータをPOSTでやり取りする」です。抽象度が高いのでもう少し言語化していきます。POSTで送信するJSON内に、ルーティングとメソッドを表すパラメータを含めて送信しGAS内でルート・メソッド判定を行い処理を振り分けることで「REST API」を再現します。以下がイメージ図ですね。
以下がrequestとresponseの例になります。実際のrequestにはHeaderだったりいろいろ付属がつくのですが、GASではそれを読むことができないのですべてJSON内に含めます。methodがHTTPメソッド部分でrouteが一般的なAPIで言うアイテム単位ですね。responseも同様にステータスコードをJSONに含めてしまいます。
以上のフォーマットを使用することで、「REST APIっぽいもの」を実装することができます。ここで注意点です。フロントエンドでは、このAPIを使用する際にはちょっとしたテクニックが必要となります。一般的なエラーハンドリングとは別のエラーハンドリングになるので気を付けてください。また、一般的なAPIとは規格が異なるので気を付けてください。
コーディング
今回の実装結果と解説です。
全体実装
今回のAPIとしては、特定のルートとメソッドを送信するとメソッドの文字列が返答されるものになります。簡易的ですがコメントを記しています。流れとしては、「受け取り→振り分け→処理→返信」といった構成になっています。公開方法に関しては、こちらの方で解説しています。
function doPost(e) {
// 返信作成用定数
const output = ContentService.createTextOutput();
output.setMimeType(ContentService.MimeType.JSON);
// PostData受け取り
const data = JSON.parse(e.postData.contents);
const path = data["path"]
const method = data["method"]
const postData = data["postData"]
let response;
switch (path) {
case "sample":
response = useSample(method, postData)
break;
default:
response = responseErrorCreate(404, "ルートの設定がされていないパラメータです")
break;
}
output.setContent(response);
return output
}
const useSample = (method, postData) => {
let result;
switch (method) {
case "GET":
result = "GET"
return responseCreate(result)
case "POST":
result = "POST"
return responseCreate(result)
case "PUT":
result = "PUT"
return responseCreate(result)
case "DELETE":
result = "DELETE"
return responseCreate(result)
default:
return responseErrorCreate(405, "不正なメソッドが送信されています")
}
}
const responseErrorCreate = (statusCode, message) => {
const response = {
statusCode: statusCode,
message: message
}
return JSON.stringify(response)
}
const responseCreate = (data) => {
const response = {
statusCode: 200,
data: data
}
return JSON.stringify(response)
}
responseクリエイト部分
const responseErrorCreate = (statusCode, message) => {
const response = {
statusCode: statusCode,
message: message
}
return JSON.stringify(response)
}
const responseCreate = (data) => {
const response = {
statusCode: 200,
data: data
}
return JSON.stringify(response)
}
若干使い方の癖があるので解説を入れておきます。responseではエラーパターンと成功パターンの2つがあるので、それぞれ関数を用意しています。エラーレスポンスでは、ステータスコードとメッセージを送信します。今回使用するステータスコードは、「200・404・405」の3つになります。この辺は、作業をしていく中で増える可能性があるのでエラーとメッセージを受け付けて返信を作成できるように構築しました。2xx番台の成功例に関しても、以降増える予定があれば書き換える必要があるかなと思いますが、今回は定数として200を返すようにします。
終わりに
今回は、GASの制限を回避して「REST APIっぽいもの」を作る手法を紹介しました。GASでは無料で扱おうとすれば制限が厳しいです。その制限を回避することができれば、ある程度のものは実装することが可能になります。取り扱いがしやすく、用意するものが少ないので初心者にとても紹介しやすい限度ですので周りの初心者さんに紹介してみてください。
ついでに記事を紹介してもらえると喜びます。こちらのライトブログでは、日々の開発の記録や知識の共有もしています。暇があれば読んでみてください。では!