This site has been updated.
Reload to display the latest version?
(click here)

Google Drive API - Script initialization

July 06, 2020
Tags: 

The basic example from the official documentation is very informative (this is not a sarcasm). I just want to add my 2 cents in order to make it more es6 like, then it is now. Plus I want one function of initialization that will take care of everything. I want to be able to run it from anywhere in the code and be sure that app will be authorized.

First I need to load the script. I want to do it dynamically from the code and not to attach it to the index.html Also this method could be called multiple times and obviously I don’t want to attach google script more than once.

import { createNanoEvents } from "nanoevents";
const emitter = createNanoEvents();

const GOOGLE_SCRIPT_ID = `apis-google-client-${getRandom(5)}`;
const DATA_LOADED_ATTR_NAME = 'data-gapi-loaded';
const SCRIPT_GAPI_LOADED = 'SCRIPT_GAPI_LOADED';

export const _load = () => new Promise((resolve) => {
    let scriptEl = <HTMLScriptElement> document.getElementById(GOOGLE_SCRIPT_ID);
    if (scriptEl) {
        if (scriptEl.getAttribute(DATA_LOADED_ATTR_NAME) !== 'true') {
            const unbind = emitter.on(SCRIPT_GAPI_LOADED, () => {
                resolve();
                // This event should be called only once.
                // Since the script is loaded only at the start of the app.
                // Therefore I'm unbounding here
                unbind();
            })
        } else {
            resolve();
        }
    } else {
        scriptEl = document.createElement('script');
        scriptEl.setAttribute('id', GOOGLE_SCRIPT_ID);
        scriptEl.setAttribute(DATA_LOADED_ATTR_NAME, 'false');
        scriptEl.src = 'https://apis.google.com/js/client.js';

        scriptEl.onload = () => {
            gapi.load('client:auth2', () => {
                scriptEl.setAttribute(DATA_LOADED_ATTR_NAME, 'true');
                emitter.emit(SCRIPT_GAPI_LOADED);
                resolve();
            });
        };

        document.body.appendChild(scriptEl);
    }
});

Next step will be gapi client initialization. The same criteria here as well - this method could be called more than once, but initialised only once:

export const _init = () => new Promise((resolve, reject) => {
    if (!gapi.client.getToken()) {
        gapi.client
            .init({
                apiKey: getApiKey(),
                clientId: getClientId(),
                discoveryDocs: DISCOVERY_DOCS,
                scope: SCOPES
            })
            .then(
                resolve,
                reject,
            );
    } else {
        resolve();
    }
});

And in the end I can combine everything in one function and use it everywhere:

export const loadAndInit = () => {
    return _load()
        .then(_init)
};