browser-samples icon indicating copy to clipboard operation
browser-samples copied to clipboard

Browser sample quickstart is obsolete

Open diguifi opened this issue 6 months ago • 6 comments

Summary

The Google Drive quickstart documentation is not working for some reason and I can't figure out why. This is the official doc page and this is the github file.

Back in 2024 I copied and ran the same quickstart code and it worked, but for some reason it's not working anymore, giving the following error:

API discovery response missing required fields.

gapix.client.GapiClientError: API discovery response missing required fields.
    at new XA (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:656:159)
    at c (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:708:48)
    at e.Cr (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:176:25)
    at Sk (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:179:59)
    at Ok (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:178:368)
    at _.xk.nz (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:178:238)
    at jk (https://apis.google.com/_/scs/abc-static/_/js/k=gapi.lb.pt_BR.ATNbtiFo1ho.O/m=client/rt=j/sv=1/d=1/ed=1/rs=AHpOoo_1YLh20Lb4BdBxVY5iwPfQkmf_Og/cb=gapi.loaded_0?le=scs:169:116)

Expected behaviour

Authenticate and show metadata for first 10 files.

Actual behaviour

Image

diguifi avatar May 07 '25 21:05 diguifi

is this repo dead?

diguifi avatar May 19 '25 01:05 diguifi

@jpoehnelt

diguifi avatar May 22 '25 15:05 diguifi

Not sure what would be causing that. The sample is fairly because and almost all of the code is related to the oauth token.

jpoehnelt avatar May 22 '25 15:05 jpoehnelt

Can you share the code you used?

// what does your code look like here?
gapi.client.drive.******

jpoehnelt avatar May 22 '25 15:05 jpoehnelt

Thank you for answering @jpoehnelt , means a lot!
Yes I use create, list and get

gapi.client.drive.files.list({})
gapi.client.drive.files.create({})
gapi.client.drive.files.get({})

But the error happens before, when its loading gapi. I didn't post code before because I literally tried running the exact code thats on the docs, no changes whatsoever, and the same error happens, at the same call.

This is how my code looks:

    <script type="text/javascript">
      const CLIENT_ID = '----------CENSORED----------';
      const GAPIK = '----------CENSORED----------';
      const DISCOVERY_DOC = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
      const SCOPES = 'https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.appfolder';

      let tokenClient;
      let gapiInited = false;
      let gisInited = false;
      let firstLoad = true;
      let loaded = false;
      const authorizeEl = document.getElementById('authorize_button');
      const loginLoadingEl = document.getElementById('login_loading');
      const loginConfirmEl = document.getElementById('login_confirmation');
      const startBtn = window.document.getElementById('confirm-btn');
      const elementToObserve = window.document.getElementById('gdrive_userdata');
      const observer = new MutationObserver(userDataChanged);
      observer.observe(elementToObserve, {characterData: false, childList: true, attributes: false});

      authorizeEl.style.visibility = 'hidden';

      function gapiLoaded() {
        gapi.load('client', initializeGapiClient);
      }

// this is where it breaks if I'm not mistaken
      async function initializeGapiClient() {
        await gapi.client.init({
          apiKey: GAPIK,
          discoveryDocs: [DISCOVERY_DOC],
        });
        gapiInited = true;
        maybeEnableButtons();
      }

      function gisLoaded() {
        let redirectUri = 'https://diguifi.itch.io/tiny-land';
        if (window.location.href.includes('localhost')) {
          redirectUri = window.location.href;
        }
        tokenClient = google.accounts.oauth2.initTokenClient({
          client_id: CLIENT_ID,
          scope: SCOPES,
          callback: redirectUri,
        });
        gisInited = true;
        maybeEnableButtons();
      }

      function maybeEnableButtons() {
        if (gapiInited && gisInited) {
          authorizeEl.style.visibility = 'visible';
        }
      }

// -----Every method bellow can be ignored but I'm leaving here for the sake of curiosity-----
      function handleAuthClick() {
        tokenClient.callback = async (resp) => {
          if (resp.error !== undefined) {
            throw (resp);
          }
          loginLoadingEl.style.display = 'block';
          startBtn.disabled = true;
          authorizeEl.style.display = 'none';
          await loadData();
        };

        if (gapi.client.getToken() === null) {
          tokenClient.requestAccessToken({prompt: 'consent'});
        } else {
          tokenClient.requestAccessToken({prompt: ''});
        }
      }

      function handleSignoutClick() {
        const token = gapi.client.getToken();
        if (token !== null) {
          google.accounts.oauth2.revoke(token.access_token);
          gapi.client.setToken('');
          authorizeEl.style.display = 'block';
          loginConfirmEl.style.display = 'none';
        }
      }

      async function loadData() {
        try {
            const response = await getAppDataFile()
            let fileId = ''
            if (response.files.length == 0) {
                const createdFile = await createAppDataFile()
                await saveAppData(createdFile.id, {data:"0"})
                fileId = createdFile.id
            } else {
                fileId = response.files[0].id
            }
            const file = await getAppDataFileContent(fileId)
            if (file) {
              loaded = true
              loginConfirmEl.style.display = 'block';
              loginLoadingEl.style.display = 'none';
              startBtn.disabled = false;
              document.getElementById('gdrive_userdata').innerHTML = file.body;
              document.getElementById('gdrive_fileid').innerHTML = fileId;
            } else {
              loginConfirmEl.innerHTML = 'Error loading data'
            }
        } catch (err) {
            return;
        }
      }

        async function getAppDataFile() {
            const result = await gapi.client.drive.files.list({
                q: 'name="tinydata.json"',
                spaces: 'appDataFolder',
                fields: 'files(id)'
            })
            return JSON.parse(result.body)
        }
        async function createAppDataFile() {
            const result = await gapi.client.drive.files
                .create({
                    resource: {
                        name: 'tinydata.json',
                        parents: ['appDataFolder']
                    },
                    fields: 'id'
                });
            return JSON.parse(result.body)
        }
        async function getAppDataFileContent(fileId) {
            return await gapi.client.drive.files
                .get({
                    fileId: fileId,
                    alt: 'media'
                });
        }
        async function saveAppData(fileId, data) {
            try { data = JSON.parse(data) } catch { }
          
            return await gapi.client.request({
                path: '/upload/drive/v3/files/' + fileId,
                method: 'PATCH',
                params: {
                    uploadType: 'media'
                },
                body: JSON.stringify(data)
            });
        }
        async function userDataChanged() {
          if (loaded && firstLoad) {
            firstLoad = false;
            return;
          }
          const newData = document.getElementById('gdrive_userdata').innerHTML
          const fileId = document.getElementById('gdrive_fileid').innerHTML
          if (newData && fileId) {
            const result = await saveAppData(fileId, newData)
          }
        }

//  here is where gis and gapi are loaded just like the docs, everything is like the docs except that I'm not listing gdrive folders, I'm saving data to the users gdrive for my app
    </script>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>

diguifi avatar May 23 '25 19:05 diguifi

@jpoehnelt I'm experiencing the exact same issue. The sample used to work fine before, but now it throws the following error:

API discovery response missing required fields.

The error occurs right after gapi.client.init, with no changes to the original code from the documentation. It seems like the Drive discovery endpoint is no longer returning the expected fields. Possibly something changed in the API or the gapi scripts that broke the integration.

andredarcie avatar Jun 08 '25 14:06 andredarcie

my small game is simply not working because of this, for the last 7 months, thats insane

diguifi avatar Jun 30 '25 22:06 diguifi

@sqrrrl please help, anyone! Theres more people with this problem: #209

diguifi avatar Jul 23 '25 03:07 diguifi

bro

diguifi avatar Aug 19 '25 22:08 diguifi

PLEASE

diguifi avatar Aug 19 '25 22:08 diguifi