FFFT

主にwebプロダクト開発に関連する話をつらつらと

5分でCloud FunctionsからCloud Storageのファイルを参照して中身を返却するAPIを作る

まずはCloud Storageに適当なバケットを作成します。
作ったバケットに適当なファイルを入れます。

自分は「test-20180903」というバケットに中身が「Hello,world」の「sample」というファイルを入れてます。
※Cloud Storageのバケット名は全世界で未使用でなければ使えないのでバケット名は被らないように適当なものを作成してください。

次にCloud Functionsです。
「関数を作成」から新規に関数を作ります。

今回は関数コード以外はいじらなくていいです。
リージョンが東京じゃなくちゃいやな人はページ下部のその他から変更してください。

まずは関数コードのpackage.jsonにCloud Storageのモジュールをdependenciesに追加します。

{
  "name": "sample-http",
  "version": "0.0.1",
  "dependencies": {
    "@google-cloud/storage": "^1.7.0"
  }
}

次にindex.jsです。

const Storage = require('@google-cloud/storage');

exports.helloWorld = (req, res) => {
  const storage = new Storage();
  const bucket = storage.bucket('test-20180903');
  const file = bucket.file('sample');
  file.download().then(function(data) {
    res.status(200).json({'result': data.toString('utf-8')});
  });
};

Cloud Functionsの設定はこれで終わりです。
保存します。

APIを叩いてみます。
保存していたら関数の詳細ページにいると思うので関数の更新が完了したらメニューから「トリガー」をクリックしてAPIのエンドポイントのリンクを押しましょう。

下記が表示されたら成功ですが失敗するかもしれません。

{"result": "Hello,world"}

上記が表示されず、エラーメッセージが表示されたらログを確認しましょう。
関数の詳細ページから「ログを表示」をクリック。

Cloud FunctionsのサービスアカウントにCloud Storageにアクセスする権限がねぇよ、的なエラーが確認できるかと思います。
※出てなかったらbucketを取得するコードをtry, catchで囲ってエラーをconsole.error()で出力させてください。

Cloud Functionsに使われているサービスアカウントはエラーログから確認できます。
こんな感じのエラーログが出てるかと思います。

ApiError: [PROJECT_ID]@appspot.gserviceaccount.com does not have storage.objects.list access to [BUCKET_NAME].

ということで対象のサービスアカウントに権限を付与しましょう。
GCPコンソールから「IAMと管理」 > 「IAM」を選択します。
対象のサービスアカウントを見つけたら右側に編集アイコンがあるので押します。

役割で「別の役割を追加」から「ストレージ」>「ストレージ オブジェクト閲覧者」を選択して保存します。

f:id:keyama4:20180903035017p:plain

改めてAPIを叩いてみたら正常に結果が確認できるかと思います。

公式には下記のような記載がありますが上記の手順で問題なくいけます。

HTTP 関数  |  Cloud Functions のドキュメント  |  Google Cloud

@google-cloud/storage ノード モジュールには、IAM(iam.googleapis.com)API と iam.serviceAccounts.signBlob 権限が必要な場合があります。次のコマンドを使用して、プロジェクトの IAM API を有効にすることができます。

しかし、Cloud Functionsめちゃ便利。
nodeのv8がまだbeta版というのが個人的には痛いですがカンタンにGCPの他のサービスと連携できちゃうのが素晴らしすぎる。