Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

dogs

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

https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get

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のサービスアカウントに目的のシートへのアクセス権をつけてやる必要があります。

https://console.cloud.google.com/functions/

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

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away