LoginSignup
5
1

More than 3 years have passed since last update.

Cloud FunctionsのTypeScriptからGoogleSheetsのデータを取得する2019

Last updated at Posted at 2019-06-11

わざわざ管理画面を作るのめんどいからGoogleSheetsで済ませたい、というのは稀に良くある状況だと思います。

dogs

みたいなスプレッドシートで管理されたデータが欲しかったとして

Google Sheets APIを利用すればCloud Functionsに限らずどこからでも何からでもアクセスは出来るんですが、Cloud Functions等の場合はデフォルトのサービスアカウントを利用する事でちょっと楽をできます。

package.json
"dependencies": {
    ...,
    "googleapis": "^39.2.0",
}
GoogleSpreadSheets.ts
import * as gapis from 'googleapis';

export class GoogleSpreadSheets {

    private auth = async (): Promise<gapis.sheets_v4.Sheets> => {
        const client = await gapis.google.auth.getClient({
            scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly']
        });
        return new gapis.sheets_v4.Sheets({ auth: client });
    }

    fetchValueRange = async (spreadsheetId: string, tabTitle: string): Promise<gapis.sheets_v4.Schema$ValueRange> => {
        const authed = await this.auth();
        const res = await authed.spreadsheets.values.get({ spreadsheetId: spreadsheetId, range: tabTitle });
        return res.data;
    }
}

spreadsheetIdというのはシートのURLにおける

https://docs.google.com/spreadsheets/d/${spreadsheetId}/

の部分で、rangeには今回の場合はタブ名を指定してますがA1:B1とかそういう書式が使えます。余談ですがGoogle Sheets APIを使っていると、Sheetsとは何かSheetとは何かみたいな迷宮へいざなわれます。

で、APIから返ってくるValueRangeを

GoogleSheetData.ts
import * as entity from '../Entity';

export class GoogleSheetData {

    private sheet: google.sheets_v4.Schema$ValueRange;
    private rows: any[];

    constructor(sheet: google.sheets_v4.Schema$ValueRange) {
        this.sheet = sheet;
        // 先頭行を飛ばしてる
        this.rows = this.rowRange().slice(1).map(this.rowValuesAt);
    }

    toDogs = (): entity.Dog[] => {
        return this.rows.map(this.toDog).filter(utils.valueIsExist);
    }

    private toDog = (row: any[]): entity.Dog | undefined => {
        const data: entity.DogData = {
            name: row[0],
            race: row[1],
        };
        if (!entity.dataIsDogData(data)) {
            console.error('GoogleSheetData.toDog %O is not DogData', data);
            return undefined;
        }
        return new entity.Dog(data);
    }

    private rowValuesAt = (i: number): any[] => {
        if (this.sheet.values === undefined) {
            return [];
        }
        return this.sheet.values[i];
    }

    private rowCount = (): number => {
        if (this.sheet.values === undefined) {
            return 0;
        }
        return this.sheet.values.length;
    }

    private rowRange = (): number[] => {
        return this.range(this.rowCount());
    }

    private range = (l: number): number[] => {
        return Array.from({ length: l }, (v, i) => i);
    };

とか何とかしてやるとシートから大量の犬を生成するコードが出来ます。でデプロイした後、最後にこのfunctionのサービスアカウントに目的のシートへのアクセス権をつけてやる必要があります。

から目的のfunctionの詳細を表示すれば利用している「サービスアカウント」の名前がわかる(Cloud Functions for Firebaseの場合も実体はCloud Functionsなので同様)ので、目的のシートを開いて右上にある共有ボタンから
共有ボタン
さっき確認したサービスアカウント名を入力して招待すれば該当シートへのアクセス権が付与されます。
招待

また権限以前にGoogle Sheets API自体を
https://console.cloud.google.com/apis/library
から有効状態にしておく必要もあります。

留意点としてGoogle Sheets APIはそこそこレスポンスが遅いので、それが問題になるようであれば1日1回とかFireStoreにでも犬達を突っ込んでおけば良いと思います。

5
1
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
5
1