Skip to content

Instantly share code, notes, and snippets.

@cantino
Last active June 16, 2018 18:28
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cantino/d1a63045fbfe5fc55a94 to your computer and use it in GitHub Desktop.
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

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

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

👍

@lightman76
Copy link

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

dklanac commented Dec 14, 2016

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

@sarafisherman22
Copy link

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