Skip to content

Instantly share code, notes, and snippets.

@cantino
Last active June 16, 2018 18:28
Show Gist options
  • Select an option

  • Save cantino/d1a63045fbfe5fc55a94 to your computer and use it in GitHub Desktop.

Select an option

Save cantino/d1a63045fbfe5fc55a94 to your computer and use it in GitHub Desktop.
Use google-api-ruby-client with the Google Contacts API
2.1.2 :004 > pp Google::Contacts.new(client).contacts
[{:emails=>{:other=>{:address=>"fake@gmail.com", :primary=>true}},
:phone_numbers=>
{:main=>"(555) 123-1234", :home=>"123-123-1234", :mobile=>"555-555-5555"},
:handles=>
{:home=>{:address=>"something", :protocol=>"AIM"},
:other=>{:address=>"something-else", :protocol=>"AIM"}},
:nickname=>nil,
:websites=>[],
:organizations=>[],
:events=>[],
:birthday=>nil,
:addresses=>
{:home=>
{:formatted_address=>"123 Fake St, New York, NY 12345",
:street=>"123 Fake St",
:city=>"New York",
:region=>"NY",
:postcode=>"12345"}},
:name_data=>
{:full_name=>"John Smith",
:given_name=>"John",
:family_name=>"Smith"},
:full_name=>"John Smith",
:primary_email=>"fake@gmail.com"},
...
]
module Google
class Contacts
attr_reader :client
def initialize(client)
@client = client
end
def execute(options = {})
client.execute({ headers: { 'GData-Version' => '3.0', 'Content-Type' => 'application/json' } }.merge(options))
end
def fetch_all(options = {})
execute(uri: "https://www.google.com/m8/feeds/contacts/default/full",
parameters: { 'alt' => 'json',
'updated-min' => options[:since] || '2011-03-16T00:00:00',
'max-results' => '100000' }).data
end
def contacts
fetch_all['feed']['entry'].map do |contact|
{
emails: extract_schema(contact['gd$email']),
phone_numbers: extract_schema(contact['gd$phoneNumber']),
handles: extract_schema(contact['gd$im']),
addresses: extract_schema(contact['gd$structuredPostalAddress']),
name_data: cleanse_gdata(contact['gd$name']),
nickname: contact['gContact$nickname'] && contact['gContact$nickname']['$t'],
websites: extract_schema(contact['gContact$website']),
organizations: extract_schema(contact['gd$organization']),
events: extract_schema(contact['gContact$event']),
birthday: contact['gContact$birthday'].try(:[], "when")
}.tap do |basic_data|
# Extract a few useful bits from the basic data
basic_data[:full_name] = basic_data[:name_data].try(:[], :full_name)
primary_email_data = basic_data[:emails].find { |type, email| email[:primary] }
if primary_email_data
basic_data[:primary_email] = primary_email_data.last[:address]
end
end
end
end
protected
# Turn an array of hashes into a hash with keys based on the original hash's 'rel' values, flatten, and cleanse.
def extract_schema(records)
(records || []).inject({}) do |memo, record|
key = (record['rel'] || 'unknown').split('#').last.to_sym
value = cleanse_gdata(record.except('rel'))
value[:primary] = true if value[:primary] == 'true' # cast to a boolean for primary entries
value[:protocol] = value[:protocol].split('#').last if value[:protocol].present? # clean namespace from handle protocols
value = value[:$t] if value[:$t].present? # flatten out entries with keys of '$t'
value = value[:href] if value.is_a?(Hash) && value.keys == [:href] # flatten out entries with keys of 'href'
memo[key] = value
memo
end
end
# Transform this
# {"gd$fullName"=>{"$t"=>"Bob Smith"},
# "gd$givenName"=>{"$t"=>"Bob"},
# "gd$familyName"=>{"$t"=>"Smith"}}
# into this
# { :full_name => "Bob Smith",
# :given_name => "Bob",
# :family_name => "Smith" }
def cleanse_gdata(hash)
(hash || {}).inject({}) do |m, (k, v)|
k = k.gsub(/\Agd\$/, '').underscore # remove leading 'gd$' on key names and switch to underscores
v = v['$t'] if v.is_a?(Hash) && v.keys == ['$t'] # flatten out { '$t' => "value" } results
m[k.to_sym] = v
m
end
end
end
end
@davidhq
Copy link
Copy Markdown

davidhq commented Aug 31, 2015

Do you know how to do this with new version of the gem?

https://github.com/google/google-api-ruby-client/blob/master/MIGRATING.md

It's not compatible and there is no Contacts API inside generated/google/apis ... thank you

@sqrrrl
Copy link
Copy Markdown

sqrrrl commented Sep 1, 2015

Mostly it's just changing client.execute to client.http. The format of the call is a little different, but still possible to use the client to make arbitrary HTTP requests.

@dimerman
Copy link
Copy Markdown

👍

@lightman76
Copy link
Copy Markdown

Thanks for this gist! In case it helps anyone, I've posted an updated gist that works with the 0.9 series of google-api-ruby-client https://gist.github.com/lightman76/2357338dcca65fd390e2 - it also has some additional methods I needed for my purposes to query contacts and retrieve groups.

@dklanac
Copy link
Copy Markdown

dklanac commented Dec 14, 2016

@lightman76 you are a life saver. Thanks so much for putting this together.

@sarafisherman22
Copy link
Copy Markdown

In this example, how do you create client?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment