Google-api-nodejs-client: directory.chromeosdevices.list() does not return nextPageToken

Created on 25 Sep 2018  路  6Comments  路  Source: googleapis/google-api-nodejs-client

  • OS: Linux
  • Node.js version: 10.10
  • googleapis version: 33.0

Steps to reproduce

  1. We have 100s of Chrome OS devices enrolled in our Google My Business domain
  2. APIs Explorer returns the nextPageToken and accepts it as input into pageToken on next list()
  3. this client library only returns data.chromeosdevices[], no nextPageToken

    data:
    { chromeosdevices:
    [ [Object],
    [Object],
    [Object],
    [Object],
    [Object],
    [Object],
    [Object],
    [Object],
    [Object],
    [Object] ] } }

Also, maxResults work for values between 1-100, but not anything larger than 100.

triage me

Most helpful comment

First, this issue should be considered closed.

Here is how I implement iterating all devices in a google domain, it should be enough to get you started:

Disclaimer.. my software syncs multiple google domain's information into my inventory system so this is how my implementation has been tailored, and specific information has been omitted, but the recursion should be straightforward.

loadSiteInfo(site, sites[site], 0, type, (site, displayName) => {
  console.info(site, displayName, 'finishing');
});

function loadSiteInfo(site, siteConfig, nextPageToken, callback) {
  getSiteData(site, siteConfig, nextPageToken)
    .then(siteDetails => {

      if (siteDetails.nextPageToken != 0 && typeof (siteDetails.nextPageToken) !== 'undefined') {
        loadSiteInfo(site, siteConfig, siteDetails.nextPageToken, callback);
      }


      if (typeof (siteDetails.nextPageToken) === 'undefined' || siteDetails.nextPageToken === 0) {
        if (typeof (callback) === 'function') {
          callback(site, siteConfig.displayName);
        }
      }
    })
    .catch(reason => {
      if (typeof (callback) === 'function') {
        callback(site, siteConfig.displayName);
      }
      console.error(reason);
    })
}


function getSiteData(site, siteConfig, pageToken) {

  var google = require('googleapis');
  var googleAuth = require('google-auth-library');

  return new Promise((fulfill, reject) => {

    var jwtClient = new google.auth.JWT(
      siteConfig.client_secret.client_email,
      null,
      siteConfig.client_secret.private_key,
      siteConfig.scopes,
      siteConfig.impersonate
    );

    jwtClient.authorize((err, tokens) => {
      if (err) {
        reject('error authenticating ' + siteConfig.displayName);
        return;
      }

      var google_admin = google.admin('directory_v1');

      var options = {};

      if (pageToken === 0) {
        options = {
          'customerId': 'my_customer',
          'auth': jwtClient
        }
      } else {
        options = {
          'customerId': 'my_customer',
          'auth': jwtClient,
          'pageToken': pageToken
        }
      }

      return google_admin.chromeosdevices.list(options, function (err, resp) {
        if( !err ) {
          var newDeviceList = resp != null && typeof resp['chromeosdevices'] !== 'undefined' ? resp['chromeosdevices'] : [];

          options.projection = "FULL";

          for (var i in newDeviceList) {
            // handle chromeosdevices
          }

          fulfill({
            site: site,
            nextPageToken: resp != null && typeof resp['nextPageToken'] !== 'undefined' ? resp['nextPageToken'] : 0,
            items: newDeviceList.length
          }) 

        } else {
          // handle rejection
          reject();
        }

      });

    });

  });
}

All 6 comments

In your options object when calling chromeosdevices.list() are you specifying pageToken: 0 ?

Example:

var pageToken = 0;
var jwtClient = <your auth class>;

var options = {
          'customerId': 'my_customer',
          'auth': jwtClient,
          'pageToken': pageToken
        }
google_admin_directory_api.chromeosdevices.list(options, function(err, resp) {
     if(!err) {
          console.log(resp['nextPageToken']);
           // do things with chromeosdevices
          // from here you can implement reassigning pageToken and 
          // iterating your calls until there is no 'nextPageToken in the response object.
     } else {
          console.error(err);
     }

})

According to the documentation here, maxResults default, and maximum, is 100.

Thanks for the suggestions. Ok, options.pageToken = 0 throws this back

errors:
[ { domain: 'global',
reason: 'invalid',
message: 'Invalid Input: 0' } ] }

options.pageToken = '' throws back
errors:
[ { domain: 'global',
reason: 'backendError',
message: 'Service unavailable. Please try again' } ] }

... and options.pageToken = '0' also throws back:
errors:
[ { domain: 'global',
reason: 'invalid',
message: 'Invalid Input: 0' } ] }

Any other ideas please?

Ahh. I took a closer look at my implementation. This is the options object I use to make the initial call.

var options = { 'customerId': 'my_customer', 'auth': jwtClient, 'projection': 'FULL', }

The response has a nextPakenToken variable how I have described in my previous answer. We use recursion to iterate our calls from there.

Interesting. If I pass a specific-set of fields to return, then I don't get a nextPageToken. I did not understand/appreciate the projection attribute you describe here. Just passing projection and not fields works for me.

Yes, recursion is the way this will have to go to fulfill an Array.concat() result set to pass back. Can you share your implementation on that? I was thinking it could be done in a Promise.all([1st, each nextPageToken ,...]), but haven't got past this "feature" of mutual exclusion between field and projection. :)

First, this issue should be considered closed.

Here is how I implement iterating all devices in a google domain, it should be enough to get you started:

Disclaimer.. my software syncs multiple google domain's information into my inventory system so this is how my implementation has been tailored, and specific information has been omitted, but the recursion should be straightforward.

loadSiteInfo(site, sites[site], 0, type, (site, displayName) => {
  console.info(site, displayName, 'finishing');
});

function loadSiteInfo(site, siteConfig, nextPageToken, callback) {
  getSiteData(site, siteConfig, nextPageToken)
    .then(siteDetails => {

      if (siteDetails.nextPageToken != 0 && typeof (siteDetails.nextPageToken) !== 'undefined') {
        loadSiteInfo(site, siteConfig, siteDetails.nextPageToken, callback);
      }


      if (typeof (siteDetails.nextPageToken) === 'undefined' || siteDetails.nextPageToken === 0) {
        if (typeof (callback) === 'function') {
          callback(site, siteConfig.displayName);
        }
      }
    })
    .catch(reason => {
      if (typeof (callback) === 'function') {
        callback(site, siteConfig.displayName);
      }
      console.error(reason);
    })
}


function getSiteData(site, siteConfig, pageToken) {

  var google = require('googleapis');
  var googleAuth = require('google-auth-library');

  return new Promise((fulfill, reject) => {

    var jwtClient = new google.auth.JWT(
      siteConfig.client_secret.client_email,
      null,
      siteConfig.client_secret.private_key,
      siteConfig.scopes,
      siteConfig.impersonate
    );

    jwtClient.authorize((err, tokens) => {
      if (err) {
        reject('error authenticating ' + siteConfig.displayName);
        return;
      }

      var google_admin = google.admin('directory_v1');

      var options = {};

      if (pageToken === 0) {
        options = {
          'customerId': 'my_customer',
          'auth': jwtClient
        }
      } else {
        options = {
          'customerId': 'my_customer',
          'auth': jwtClient,
          'pageToken': pageToken
        }
      }

      return google_admin.chromeosdevices.list(options, function (err, resp) {
        if( !err ) {
          var newDeviceList = resp != null && typeof resp['chromeosdevices'] !== 'undefined' ? resp['chromeosdevices'] : [];

          options.projection = "FULL";

          for (var i in newDeviceList) {
            // handle chromeosdevices
          }

          fulfill({
            site: site,
            nextPageToken: resp != null && typeof resp['nextPageToken'] !== 'undefined' ? resp['nextPageToken'] : 0,
            items: newDeviceList.length
          }) 

        } else {
          // handle rejection
          reject();
        }

      });

    });

  });
}

Yes, I agree this issue should be closed. Thank you for engaging and your code example.

Was this page helpful?
0 / 5 - 0 ratings