0
0

NodeからBigQueryアクセス

Posted at

1. はじめに

Reactでサービスを作るにあたって、そのログをBigQueryへ格納しようと思います。なので、サーバー側のアプリケーションからBQへの、接続の技術検証です。
GCPの公式リファレンス( Node.js client library  |  Google Cloud )を参考にし、イチから構築します。

ソースは下記にあります。

2. 準備

2.1. サーバーアプリを作成

あるURLを指定されたら、BigQueryへInsertするサーバーアプリを作ります。でもその部分は後で実装するとして、まずはexpressで超単純な普通のWebサーバー「log_server」を作ります。

expressを初期構築。package.jsonのmainをapp.jsにするって書いてあるけど、今回の作業には関係ないのでスルー。ついでに、.envを読むためのdotenvというモジュールもインストールします。

$ mkdir log_server
$ cd log_server
$ npm init -y
$ npm install express dotenv

app.jsを作成。後で、登録(post)を作る予定です。ログを登録するだけなので参照(get)はなし!

react_prac_using_bq/log_server/app.js
require('dotenv').config();
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

起動して動作確認。下記を実行して、http://localhost:3000でHello Worldが出ればOK。

$ node app.js

2.2. GCPのプロジェクト作成

いったんコーディングから離れて、GCPの操作です。参考:Node.js client library  |  Google Cloud
まずはプロジェクトを作成します。

  • プロジェクト名: survey-node-to-bq

API呼び出しによって費用が発生します。なので、無料期間が終わっている場合は、billingの設定が必要です。無料でできる範囲もあるかもしれませんが、基本的にビジネスで使うので、無料範囲の詳細は今は調べません。
技術検証の目的の場合は、プロジェクトを作って、調べ終わったら、プロジェクトごと削除(シャットダウン)するとよいです。これはGCPの手順書によく書いてある方法で、削除すれば完全に費用はかからないです。

なお、GCPの手順書によるとAPIを有効にする手順がありましたが、BigQuery APIは最初から有効化されていて、「APIとサービス」で有効化する必要はありませんでした。

2.3. BigQueryにテーブルを作成

ここも詳細は割愛。ログを想定しているのでそれっぽく。

  • データセット: app_logs
  • テーブル: button_clicked_log
    • ボタンをクリックしたらBigQueryに1レコード追加するアプリを作る予定
    • 項目は、文字列と数値を入れる感じで適当に
      image.png

2.4. 認証情報をゲットして設定

ここ、私は苦手分野なので、手厚めに。

2.4.1. 読み物

クライアント ライブラリを使用して認証する  |  Google Cloud
(要約)
「クライアントライブラリ」を使えば簡単。
「クライアントライブラリ」は、内部で「アプリケーションのデフォルト認証情報(ADC)」という道具を使う。そのためにADCの設定が必要。

アプリケーションのデフォルト認証情報を設定する  |  Google Cloud
(要約)
ADCの認証設定は、プログラムの種類によって、4つに分けられる。

  • ① ローカルで動かすプログラム
    • Google Cloud CLIの情報を使う
      • コマンドラインのGCP操作ツールでログインするんだから、それを使えば簡単。
      • ただし開発中のみ使える。逆に言うと本番では使わない。というかローカルの本番ってなんだろう??
    • サービスアカウント(SA)認証情報
      • SAを発行して認証する
      • SAの権限借用を
        • 使用する場合
        • 使用しない場合 :point_left::point_left:今回はこれ
          • JSONファイルをダウンロードして、そのパスを環境変数へ設定する
  • ② GCP内にプログラムを置くパターンのプログラム
    • 基本的に不要。必要ならSAを使う。
  • ③ GCPサービスの設定で、SAを指定できるパターンのプログラム
  • ④ オンプレミス or どこかのクラウド
    • Workload Identity か、SAを使う

2.4.2. GCP関連の手順

  1. GCPの「IAMと管理」>「サービスアカウント」で、サービスアカウントを作成。
    • アカウント名: sa_for_button_clicked_app
    • ロール
      • BigQueryジョブユーザー
        • クエリを投げる権限
        • "どこへ"という情報はなく、ただ投げる権限。ないと投げられない。
        • ジョブユーザー<ユーザー<管理者 という包括関係。
          • ユーザーは、一覧を見られる権限も付く。
          • 一覧なんて見なくても、扱うテーブルが決まってるなら、ジョブユーザーで十分。
      • BigQueryデータ編集者
        • 閲覧者<編集者<オーナー という包括関係。
        • オプションでテーブルを指定できるけど、まぁ全部でいいや。
    • ユーザーにSAへのアクセス:許可しない
  2. GCPの画面の、作ったSAの名前のリンクから、「キー」>「鍵を追加」>「新しい鍵を作成」>「JSON」で、jsonファイルをゲットする。
  3. ゲットしたjsonファイルの名前を適当に変える。survey-node-to-bq.jsonにしました。

2.4.3. サーバーの認証設定

次はソースに戻ります。

  1. log_server/.gitignore ファイルを作る
  2. log_server/.gitignore ファイルに /credentialsを追記する
  3. log_server/credentials フォルダを作る
  4. GCPからゲットしてリネームしたsurvey-node-to-bq.jsonを格納する
    • log_server/credentials/survey-node-to-bq.json となります。
  5. log_server/.env ファイルを作成し、jsonのパスを設定する
log_server/.env
GOOGLE_APPLICATION_CREDENTIALS="./credentials/survey-node-to-bq.json"

ここで、git statusして、現れないことを確認します。必須。後回しにせず、いまこのタイミングでやるべき。
これをやらないと悪用され、Googleから大きな課金請求が来る可能性があるので、本当に慎重・確実に。

3. BigQueryへの連携<本題>

ここからが本題。

サーバーへ、Googleのモジュールをインストール。

$ npm install @google-cloud/bigquery

app.jsを修正します。トップの/のget処理を消し、ログ登録の/logのpost処理を追加。
本筋ではありませんが、リクエスト時にJSONで渡したいので、JSONパーサーの設定もしてます。

log_server/app.js
require('dotenv').config();
const express = require('express');
const app = express();
const bodyParser = require('body-parser')
const port = 3000;

// JSONパーサー
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(bodyParser.json());

// ログ登録
app.post("/log", (req, res) => {
    res.send("Recieved POST request!");
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});

ログ登録のところに、BQへ登録する処理を追加します。

長く書いちゃったけど、悩みポイントはあんまりないはず。非同期処理で、Promiseインスタンスのthen()catch()を使います。

log_server/app.js
省略
// Google Cloud client library をインポート
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery({
    projectId: "survey-node-to-bq",
});
省略
// ログ登録
app.post("/log", (req, res) => {
    const val1 = req.body.val1;
    const val2 = req.body.val2;
    const int1 = req.body.int1;
    const float1 = req.body.float1;

    const now = new Date();
    const now_str = 
        `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()} ` +
        `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
    bigquery.query(
        "insert into `survey-node-to-bq.app_logs.button_clicked_log`"
        + `values ("${now_str}", "${val1}", "${val2}", ${int1}, ${float1});`
    ).then(data => {
        console.log("inserted!");
    }).catch(error => {
        console.log("ERROR OCCURRED!!");
        console.log(error);
    });

    res.send("Recieved POST request!");
});
省略

PostmanなどでPOSTを投げてテストするとよいです。curlでもいい。(詳細は割愛)

4. おわりに

GoogleのADCの説明は、いろいろなケースを書いてるから、とても大きなドキュメントになっていて敷居が高かったですが、じっくり読めばなんとか。。結果的にいくつかのケースのうちの1つしかやらないわけで、やることはそんなに多くはないです。でも疲れた。

個人的な学びとして、素人感丸出しですが、この作業によってサーバーとクライアントの役割が腑に落ちました。Reactだけでnpm run startでできてそうなのに、なぜExpressとかサーバー系が必要なの??って、まったく理解できていませんでした。React Routerとか"ぽい"やつがあることも初心者、少なくとも私にはノイズだったのかも。

わかってないせいで、Reactの中のコンポーネントに@google-cloud/bigqueryをインストールし、実行して、fsがない的なエラーが出てました。独学者でこの悩み持ってる人、一定数いると思う。つまみ食いで作りたいものだけ作ってみて、体系的に勉強しないことも一因か。

まぁ結果的にできてよかったです。これができればBQへの問い合わせもできるだろうし、GCSの操作もできそう。一気に道具が増えました!

5. 参考にしたサイトのまとめ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0