Search code examples
google-sheetsgoogle-apps-scripthttp-status-code-404google-people-api

Google App Script People API updateContact() Error 404


I'm using Google App Script to try to update google contacts with data from google sheet, but I received Error 404. I wonder what have I missed?

Here below my code.

I first gather data from sheet to arrays, then feed values of arrays into "resource", then I update contact by contact (because I don't know how to use the batchupdate).


function updateContactsFromSheet() {
  var sheetId = '[SheetID]';
  var sheetName = '[SheetName]';

  var sheet = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);
  var dataRange = sheet.getDataRange();
  var data = dataRange.getValues();

  var headerRow = data[0];
  var emailColumnIndex = headerRow.indexOf('Email');
  var firstNameColumnIndex = headerRow.indexOf('First Name');
  var middleNameColumnIndex = headerRow.indexOf('Middle Name');
  var lastNameColumnIndex = headerRow.indexOf('Last Name');
  var phoneColumnIndex = headerRow.indexOf('Mobile');
  var resourceNameColumnIndex = headerRow.indexOf('resourceName');
  var etagColumnIndex = headerRow.indexOf('etag');


  for (var i = 1; i < data.length; i++) {

    var resource = {
    names: [],
    emailAddresses: [],
    phoneNumbers: [],
    etag: []
  };

    var row = data[i];
    var email = row[emailColumnIndex];
    var firstName = row[firstNameColumnIndex];
    var middleName = row[middleNameColumnIndex];
    var lastName = row[lastNameColumnIndex];
    var phone = row[phoneColumnIndex];
    var resourceName = row[resourceNameColumnIndex];
    var etag =  row[etagColumnIndex];

    if(resourceName != ''){

    resource.names.push({
      givenName: firstName,
      middleName: middleName,
      familyName: lastName
    });
    resource.emailAddresses.push({ value: email });
    resource.phoneNumbers.push({ value: phone });
    resource.etag.push(etag);

    People.People.updateContact(resource, resource.resourceName);

  }
}
}


Here's the error:

HttpResponseException: Response Code: 404. Message: <!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 404 (Not Found)!!1</title>
  <style>

Solution

  • IMPORTANT:

    In this answer, if the values of resourceName and etag are invalid values, the script cannot be used. And, if you have no permission to update the contacts, this script cannot be used. Please be careful about this.

    Modification points:

    • In your script, I think that resource.resourceName is undefined. I thought that this might be the reason for your current issue.
    • In this case, it is required to use updatePersonFields.
    • etag is required to be a string instead of an array.

    When your showing script is modified with these modification points, it becomes as follows.

    Modified script 1:

    In this modification, your script is modified.

    function updateContactsFromSheet() {
      var sheetId = '[SheetID]';
      var sheetName = '[SheetName]';
    
      var sheet = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);
      var dataRange = sheet.getDataRange();
      var data = dataRange.getDisplayValues();
      var headerRow = data[0];
      var emailColumnIndex = headerRow.indexOf('Email');
      var firstNameColumnIndex = headerRow.indexOf('First Name');
      var middleNameColumnIndex = headerRow.indexOf('Middle Name');
      var lastNameColumnIndex = headerRow.indexOf('Last Name');
      var phoneColumnIndex = headerRow.indexOf('Mobile');
      var resourceNameColumnIndex = headerRow.indexOf('resourceName');
      var etagColumnIndex = headerRow.indexOf('etag');
      for (var i = 1; i < data.length; i++) {
        var resource = { names: [], emailAddresses: [], phoneNumbers: [] };
        var row = data[i];
        var email = row[emailColumnIndex];
        var firstName = row[firstNameColumnIndex];
        var middleName = row[middleNameColumnIndex];
        var lastName = row[lastNameColumnIndex];
        var phone = row[phoneColumnIndex];
        var resourceName = row[resourceNameColumnIndex];
        var etag = row[etagColumnIndex];
        if (resourceName != '') {
          resource.names.push({ givenName: firstName, middleName: middleName, familyName: lastName });
          resource.emailAddresses.push({ value: email });
          resource.phoneNumbers.push({ value: phone });
          resource.etag = etag;
          People.People.updateContact(resource, resourceName, { updatePersonFields: "names,emailAddresses,phoneNumbers" });
        }
      }
    }
    

    Modified script 2:

    From because I don't know how to use the batchupdate. if you wanted to use Method: people.batchUpdateContacts, it becomes as follows.

    function updateContactsFromSheet() {
      var sheetId = '[SheetID]';
      var sheetName = '[SheetName]';
    
      var sheet = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);
      var dataRange = sheet.getDataRange();
      var [headerRow, ...data] = dataRange.getDisplayValues();
      var emailColumnIndex = headerRow.indexOf('Email');
      var firstNameColumnIndex = headerRow.indexOf('First Name');
      var middleNameColumnIndex = headerRow.indexOf('Middle Name');
      var lastNameColumnIndex = headerRow.indexOf('Last Name');
      var phoneColumnIndex = headerRow.indexOf('Mobile');
      var resourceNameColumnIndex = headerRow.indexOf('resourceName');
      var etagColumnIndex = headerRow.indexOf('etag');
      var contacts = data.reduce((ar, row) => {
        var resource = { names: [], emailAddresses: [], phoneNumbers: [] };
        var email = row[emailColumnIndex];
        var firstName = row[firstNameColumnIndex];
        var middleName = row[middleNameColumnIndex];
        var lastName = row[lastNameColumnIndex];
        var phone = row[phoneColumnIndex];
        var resourceName = row[resourceNameColumnIndex];
        var etag = row[etagColumnIndex];
        if (resourceName != '') {
          resource.names.push({ givenName: firstName, middleName: middleName, familyName: lastName });
          resource.emailAddresses.push({ value: email });
          resource.phoneNumbers.push({ value: phone });
          resource.etag = etag;
          ar.push([resourceName, resource]);
        }
        return ar;
      }, []);
      if (contacts.length == 0) return;
      const reqs = [...Array(Math.ceil(contacts.length / 200))].map(_ => contacts.splice(0, 200).reduce((o, [a, b]) => (o[a] = b, o), {}));
      reqs.forEach(r => People.People.batchUpdateContacts({ contacts: r, updateMask: "names,emailAddresses,phoneNumbers" }));
    }
    
    • In the case of People.People.batchUpdateContacts, the maximum chunk size is 200 contacts for every request.

    Note:

    • About both scripts, when the values of resourceName and etag are valid values and you have permission to update the contacts, the script works fine.

    References: