How to asynchronuosly contruct a DataSource?

I’m trying to create a DataSources class that interacts with Google Sheets via Sheets API

To start reading sheets, the API needs to do an asynchronous authorization process. How should I write my class since it relies exclusively on this async event?

The auth process goes something like this:

authorize(credentials).then(auth => {

 // I have to init the api here because it needs an auth object returned asynchronously
 const api = google.sheets({ version: "v4", auth });

});

How should I initialize the class so I can use api inside every method?

import { google } from "googleapis";
import * as fs from "fs";
import { authorize, CRED_PATH } from "../../sheetsAuth";
import { DataSource } from "apollo-datasource";

class SheetsAPI extends DataSource {
  sheetID: any;
  api: any;
  constructor(sheetID) {
    super();
    this.sheetID = sheetID;
    // ideally I initialize the api here, but is asynchronous
    authorize(credentials).then(auth => {
        this.api = google.sheets({ version: "v4", auth });
    });
  }

  async getRows() {
    // ideally I want to have access to the authorized api here but since its async it returns undefined
     
    const r = await this.api.spreadsheets.values.get({
      spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
      range: "Class Data!A2:E",
    });
    if (r) {
      const rows = r.data.values;
      if (rows) {
        if (rows.length) {
          return rows;
        }
      }
    }
  }
}

export { SheetsAPI };

How can I overcome this?

5 thoughts on “How to asynchronuosly contruct a DataSource?”

  1. Right now I decided to go with this approach:

    Create a special method to initialize the authorization before every method call.

    class SheetsAPI extends DataSource {
      sheetID: any;
      api: any;
      constructor(sheetID) {
        super();
        this.sheetID = sheetID;
      }
    
      async init() {
        //init returns a promise I can await so I'm sure this.api will be defined before I use it
        const auth = authorize(JSON.parse(fs.readFileSync(CRED_PATH, "utf8"))).then(
          (auth) => {
            this.api = google.sheets({ version: "v4", auth });
          }
        );
      }
    
      async getRows() {
        // I have to await this.init every time I need to use this.api
        await this.init();
    
        const r = await this.api.spreadsheets.values.get({
          spreadsheetId: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          range: "Class Data!A2:E",
        });
        if (r) {
          const rows = r.data.values;
          if (rows) {
            if (rows.length) {
              return rows;
            }
          }
        }
      }
    }
    
    Reply

Leave a Comment