##はじめに
AWSのサービスとGAS(Google Apps Script)を使用して以下のようなチャットアプリを作成しました!
(詳細については【初心者向け】初めてのチャットアプリ作成〜AWSを使ったサバーレスアーキテクチャ〜を参照してください)
例に漏れず、問題(そり立つ壁)にぶつかったのでメモとして残していきます。。
##目次
1.全体像について
2.問題点について
3.どうやって解決したか
4.まとめ
詳しい処理の説明は別の記事に記載しているため省きますが、各サービスの役割について簡単にまとめておきます。
・GAS:画面から入力された日本語を英語に翻訳し、変換する
・DynamoDB:画面から入力されたコメントを部屋の名前をキーとして保存する
・Lambda:画面から入力されたコメントをDynamoDBへ保存する
DynamoDBのコメントを画面に返却する
・API Gateway:エンドポイントとして画面とLambdaをつなぐ
・S3:静的Webサイトをホスティングする
以前作成したWebサイト「Man in the Mirror」で使用したサービスはS3だけでしたが、
今回は複数のサービスを使用したため、サービス間の接続でいくつか問題が発生しました...
(エラーが発生しすぎてサ◯マ◯クカフェで発狂したのも今ではいいおもひで(泣))
次章ではその問題についてどう対応したのかを説明します。
##2.問題点について
特に以下の処理で苦労しました。
######(1)axiosによるGAS・Lambda呼び出しについて
今回のアプリではGASとLmabdaを呼び出して以下のような処理をしています。
①画面入力された日本語をGASに連携し、英語に翻訳する
②GASから返却された英語をDynamoDBに登録する
③DynamoDBに登録されているコメント履歴を取得し、画面に表示する
ですので以下のようにプログラミングしました。
// Lambda呼び出し用のAxiosオブジェクト
const requestAws = axios.create({});
// GAS呼び出し用のAxiosオブジェクト
const requestGas = axios.create({});
// 画面から入力されたコメント
let comment = "";
// GASにて翻訳したコメント
let translatedComment = "";
// 画面に表示するトーク履歴
let commentList = new Array();
// コメントNo(Lambda呼び出し時点でこのNoよりも最新のコメントを全て取得する)
let commentNo = 0;
// ルーム名(DynamoDBに格納するコメントリストのキーとして使用)
let roomName = "[ルーム名]";
/** Google Apps ScriptのAPI呼び出し処理(Get)
* リクエスト
* ・text: 画面入力されたコメント(comment)
* ・source: 編訳対象のコメントの言語(日本語の場合は"ja")
* ・target: 翻訳語のコメントの言語(英語の場合は"en")
* リザルト
* ・text: targetの言語に翻訳されたtext
**/
requestGas
.get("[GASのURL]" + "?text=" + comment + "&source=ja&target=en")
.then(function(response) {
// リザルトのtextを格納する
translatedComment = response.data;
});
/** AWS LambdaのAPI呼び出し処理(Post)
* リクエスト
* ・roomName: 画面入力されたルーム名
* ・comment: 英語翻訳されたコメント(translatedComment)
* ・commentNo: 現在表示されているコメントの最新No
* リザルト
* ・commentList: ルーム名に紐付くコメントリスト
* (commemtNo以降のコメントリスト)
**/
requestAws
.post("[API Gatewayのエンドポイント]", {
roomName: roomName,
comment: translatedComment,
commentNo: commentNo
})
.then(function(response) {
// リザルトのcommentListを格納する
commentList = response.data;
// コメントリストの画面表示処理呼び出し
showCommentList(commentList);
});
各サービスの呼び出し処理はaxios
を使用しています。
axios
の説明、使い方については以下のサイトのご説明を参考とさせていただきました。
・[フロントエンド] axiosライブラリを使って、柔軟にHTTP通信を行う
・[axios] axios の導入と簡単な使い方
まず、画面から入力されたコメントをcomment
に格納し、GASにて英語に翻訳します。
次に、GASの処理で翻訳したコメントをtranslatedComment
に格納し、
roomName
・commentNo
と共にLambdaに連携します。
そして、Lambdaにて連携されたtranslatedComment
をroomName
をキーとして
DynamoDBに保存し、commentNo
より最新のコメントをcommentList
に格納し、
返却します。
最後に、返却されたcommentList
を画面に表示します。
その実行結果がこちらです!!
こちらの問題はaxios
について理解が不足していたことが原因でした...
詳しくは次章で説明します。
######(2)S3・API GatewayのCORS設定について
今回のチャットアプリは、前回作成したWebサイトと同様に
S3のホスティング機能を使用しました。
AWSのサービス間のイメージとしては以下の通り
LambdaやGASを含めた全ての実装が完了し、ローカル環境でテストを実施して
問題ないことが確認できたので、いよいよS3にアップロード!!
無事アップロードが完了したため、S3から呼び出してみたところ
「access-control-allow-origin」に関連するエラーが複数発生していた...
##3.どうやって解決したか
######(1)axiosによるGAS・Lambda呼び出し の解決について
原因はaxiosについての理解不足でした。
axiosはPromiseベースです。
Promiseについては以下のサイトをご参照願います。
Promiseによる非同期処理[resolve][reject][Promise.all]
axiosでは処理(ここではGAS・Lambda呼び出し処理)の結果が正常に終了した場合、then
以降の処理が実行されます。
つまり
①GAS呼び出し が正常に終了した後に ②Lambda呼び出し を実行する必要があるため、
①GAS呼び出しのthen
メソッド内で ②Lambda呼び出し を実行すれば良いと考えました。
そして、修正した処理がこちらです。
// Lambda呼び出し用のAxiosオブジェクト
const requestAws = axios.create({});
// GAS呼び出し用のAxiosオブジェクト
const requestGas = axios.create({});
// 画面から入力されたコメント
let comment = "";
// GASにて翻訳したコメント
let translatedComment = "";
// 画面に表示するトーク履歴
let commentList = new Array();
// コメントNo(Lambda呼び出し時点でこのNoよりも最新のコメントを全て取得する)
let commentNo = 0;
// ルーム名(DynamoDBに格納するコメントリストのキーとして使用)
let roomName = "[ルーム名]";
/** Google Apps ScriptのAPI呼び出し処理(Get)
* リクエスト
* ・text: 画面入力されたコメント(comment)
* ・source: 編訳対象のコメントの言語(日本語の場合は"ja")
* ・target: 翻訳語のコメントの言語(英語の場合は"en")
* リザルト
* ・text: targetの言語に翻訳されたtext
**/
requestGas
.get("[GASのURL]" + "?text=" + comment + "&source=ja&target=en")
.then(function(response) {
// リザルトのtextを格納する
translatedComment = response.data;
/** AWS LambdaのAPI呼び出し処理(Post)
* リクエスト
* ・roomName: 画面入力されたルーム名
* ・comment: 英語翻訳されたコメント(translatedComment)
* ・commentNo: 現在表示されているコメントの最新No
* リザルト
* ・commentList: ルーム名に紐付くコメントリスト
* (commemtNo以降のコメントリスト)
**/
requestAws
.post("[API Gatewayのエンドポイント]", {
roomName: roomName,
comment: translatedComment,
commentNo: commentNo
})
.then(function(response) {
// リザルトのcommentListを格納する
commentList = response.data;
// コメントリストの画面表示処理呼び出し
showCommentList(commentList);
});
});
画面から入力した「こんにちは」を英語に翻訳し、「HELLO」と表示できました!!!
######(2)S3・API GatewayのCORS設定 の解決について
すでに表題で書いていますが、S3とAPI GatewayのCORS設定がされていなかったことが原因でした。
CORSについては以下の記事にて詳細に記載されております。
CORSまとめ
今回はS3にHTML、Javascriptをアップロードしています。
そのため、S3以外へのHTTP通信(Lambda等の他のWebサービス呼び出す)は
同一オリジンポリシーに反するため、エラーが発生していました。
この問題を解決するためにCORSの設定が必要となります。
CORSの設定は以下の通り。
設定値については以下の通り
・AllowedOrigin
クロスドメインリクエストを許可するオリジンを指定します ( http://www.example.com など)
今回は*
を指定して、Lambda等からクロスオリジンリクエストを送信できるようにしました。
・AllowedMethod
どのHTTPリクエストメソッドを許可するのかを設定できます。
今回はGET通信とPOST通信を使用するため、それぞれ設定しています。
・AllowedHeader
どのHTTPリクエストヘッダを許可するのかを設定できます。
こちらで設定されているヘッダのみをレスポンス時に設定できます。
今回は*
を設定しました。
詳しい設定方法は公式ドキュメントをご参照ください。
設定値については以下の通り(全てデフォルトの設定です)
・Access-Control-Allow-Methods
リソースへアクセスできるHTTPリクエストメソッドを指定します。
・Access-Control-Allow-Headers
どのHTTPリクエストヘッダを許可するのかを設定できます。
・Access-Control-Allow-Origin
どのHTTPリクエストオリジンを許可できるのかを設定できます。
ちなみにAPI Gatewayの設定を行った後は必ずデプロイしてください..
(私はデプロイするのを忘れていたため、1時間無駄にしました...)
##4.まとめ
今回も様々な問題にぶつかりましたが、なんとか2つ目の実装が完了しました。
また、今回の問題解決にはQuitaのたくさんの投稿者皆様の記事を参考にさせていただきました。
この場を借りてお礼申し上げます。