2
votes

Is there a way to batch CRUD contacts with the new google people api (i see getBatchGet exists for READS)? My app is gonna hit ratelimits left and right if we upgrade from the old gdata contacts api.

2

2 Answers

1
votes

Follow the Google People APIs to learn how to populate your objects, the most important part is the way of using Google Batch API in a do-while loop:


const { google }  = require('googleapis')


function extractJSON (str) {
  const result = []

  let firstOpen  = 0
  let firstClose = 0
  let candidate  = 0

  firstOpen = str.indexOf('{', firstOpen + 1)

  do {
    firstClose = str.lastIndexOf('}')

    if ( firstClose <= firstOpen ) {
      return []
    }

    do {
      candidate = str.substring(firstOpen, firstClose + 1)

      try {
        result.push(JSON.parse(candidate))
        firstOpen = firstClose
      } catch (e) {
        firstClose = str.substr(0, firstClose).lastIndexOf('}')
      }

    } while ( firstClose > firstOpen )

    firstOpen = str.indexOf('{', firstOpen + 1)

  } while ( firstOpen !== -1 )

  return result
}

async function batchDeleteContacts (resourceIds) {
  /*
    resourceIds = [
      'c1504716451892127784',
      'c1504716451892127785',
      'c1504716451892127786,
      ....'
    ]


    Setup your google-api client and extract the oauth header/
  */
  const authHeader = await google.oAuth2Client.getRequestHeaders()

  let counter   = 0
  let confirmed = []

  try {
    do {
      const temp = resourceIds.splice(0, 25)

      const multipart = temp.map((resourceId, index) => ({
        'Content-Type': 'application/http',
        'Content-ID': (counter * 25) + index,
        'body': `DELETE /v1/people/${resourceId}:deleteContact HTTP/1.1\n`
      }))

      const responseString = await request.post({
        url: 'https://people.googleapis.com/batch',
        method: 'POST',
        multipart: multipart,
        headers: {
          'Authorization': authHeader.Authorization,
          'content-type': 'multipart/mixed'
        }
      })

      const result = extractJSON(responseString)
      confirmed = confirmed.concat(result)

      counter ++

    } while ( resourceIds.length > 0 )

  } catch (ex) {

    // Handling exception here
  }

  return confirmed
}

async function batchInsertContacts (contacts) {
  /*
    Follow the Google People APIs documentation to learn how to generate contact objects,
    Its easy and depends on your needs.

    contacts = [{
      resource: {
        clientData,
        names,
        nicknames,
        birthdays,
        urls,
        addresses,
        emailAddresses,
        phoneNumbers,
        biographies,
        organizations
      }
    }]

    Setup your google-api client and extract the oauth header/
  */
  const authHeader = await google.oAuth2Client.getRequestHeaders()

  let counter   = 0
  let confirmed = []

  const authHeader = await this.oAuth2Client.getRequestHeaders()

  try {
    do {
      const temp = contacts.splice(0, 25)

      const multipart = temp.map((contact, index) => ({
        'Content-Type': 'application/http',
        'Content-ID': (counter * 25) + index,
        'body': 'POST /v1/people:createContact HTTP/1.1\n'
              + 'Content-Type: application/json\n\n'
              + JSON.stringify(contact.resource)
      }))

      const responseString = await request.post({
        url: 'https://people.googleapis.com/batch',
        method: 'POST',
        multipart: multipart,
        headers: {
          'Authorization': authHeader.Authorization,
          'content-type': 'multipart/mixed'
        }
      })

      const result = extractJSON(responseString)
      confirmed = confirmed.concat(result)

      counter ++

    } while ( contacts.length > 0 )

  } catch (ex) {

    // Handling exception here
  }

  return confirmed
}

async function batchUpdateContacts (contacts) {
  /*
    Follow the Google People APIs documentation to learn how to generate contact objects,
    Its easy and depends on your needs.

    contacts = [{
      resourceId: 'c1504616451882127785'
      resource: {
        clientData,
        names,
        nicknames,
        birthdays,
        urls,
        addresses,
        emailAddresses,
        phoneNumbers,
        biographies,
        organizations
      }
    }]

    Setup your google-api client and extract the oauth header/
  */
  const authHeader = await google.oAuth2Client.getRequestHeaders()

  const updatePersonFields = 'names,nicknames,birthdays,urls,addresses,emailAddresses,phoneNumbers,biographies,organizations'

  let counter   = 0
  let confirmed = []

  const authHeader = await this.oAuth2Client.getRequestHeaders()

  try {
    do {
      const temp = contacts.splice(0, 25)

      const multipart = temp.map((contact, index) => ({
        'Content-Type': 'application/http',
        'Content-ID': (counter * 25) + index,
        'body': `PATCH /v1/people/${contact.resourceId}:updateContact?updatePersonFields=${updatePersonFields} HTTP/1.1\n`
              + 'Content-Type: application/json\n\n'
              + JSON.stringify(contact.resource)
      }))

      const responseString = await request.post({
        url: 'https://people.googleapis.com/batch',
        method: 'POST',
        multipart: multipart,
        headers: {
          'Authorization': authHeader.Authorization,
          'content-type': 'multipart/mixed'
        }
      })

      const result = extractJSON(responseString)
      confirmed = confirmed.concat(result)

      counter ++

    } while ( contacts.length > 0 )

  } catch (ex) {

    // Handling exception here
  }

  return confirmed
}
0
votes

Short answer: no.

However, you may be able to prevent rate limiting with the quotaUser query param on your requests.

  • Lets you enforce per-user quotas from a server-side application even in cases when the user's IP address is unknown. This can occur, for example, with applications that run cron jobs on App Engine on a user's behalf.
  • You can choose any arbitrary string that uniquely identifies a user, but it is limited to 40 characters.

I have been using the People API on a new development. Seems pretty limited, e.g. contact search isn't even available yet. I'd keep the Contacts API/GData around for features that aren't available in the newer API yet.