My favorites | English | Sign in

Google Health Data API

Developer's Guide: Python

Google provides a Google Health extension to the Google Data Python client library that helps connect to and use the Health Data API. In addition to providing some background on the capabilities of the Health Data API, this guide provides examples for interacting with the API using the Python client library. If you're interested in understanding more about the underlying protocol used by the Python client library to interact with the Health API, please see the protocol guide. For help setting up the client library, see the article on Getting Started with the Google Data Python Client Library.

Contents

Audience

This document is intended for programmers who want to write Python applications that interact with Google Health. The following instructions assume some knowledge of building, deploying, and running Python console/web applications.

Introduction

The Google Data Python Client Library includes extensions to most Google Health-specific objects to make the service easier to use.

The Atom XML in a feed or entry is mapped to corresponding class in the Python library. For example, the <atom:feed> element and <atom:entry> element correspond to the gdata.health.ProfileFeed and gdata.health.ProfileEntry classes, respectively.

This client library is by no means the only way of connecting to and using the Google Health API. If you're interested in reading more about the underlying protocol that this library uses, see the Developer's Guide which discusses the raw protocol.

Google Health extends the Google Data feeds with elements from the ccr namespace. A user's entire Google Health profile is stored in the Continuity of Care Record. This CCR data corresponds to an instance of the class gdata.health.Ccr.

Getting started

The Google Health APIs utilizes Google Accounts for authentication, so if you have a Google account you are all set. Otherwise, you can create a new account.

To use the Python client library, you'll need Python 2.0+ and the modules listed on the DependencyModules wiki page. After downloading the client library, a general introduction to the Python Client Library is available in the article Getting Started with the Google Data Python Library.

To include the examples in this guide into your own code, you'll need the following import statement:

import gdata.health
import gdata.health.service

You will also need to setup a HealthService object, which represents a client connection (with authentication) to the Health API.

client = gdata.health.service.HealthService(source='yourCo-yourAppName-v1')

To setup your HealthService to work with /h9, use:

client = gdata.health.service.HealthService(source='yourCo-yourAppName-v1', use_h9_sandbox=True)

The source argument is optional and should follow the format: company-applicationname-version. It's recommended to include this parameter for logging purposes.

Note: The rest of the guide assumes you've created a HealthService in the variable client.

Back to top

Authenticating to the Health service

ClientLogin for "installed" applications

Use ClientLogin authentication if your client is a standalone, single-user "installed" client (such as a desktop/console application). Once you have created a HealthService for either /h9 or /health, call the gdata.service.ClientLogin() method with the user's credentials to authenticate your client.

client.ClientLogin('user@gmail.com, 'pa$$word')

For more information about ClientLogin authentication, including sample requests and responses, see the Authentication for Installed Applications documentation.

Note: As described in the ClientLogin documentation, the authentication request may fail and issue a CAPTCHA challenge. If you want Google to display and handle the CAPTCHA challenge, then send the user to https://www.google.com/accounts/DisplayUnlockCaptcha?service=health (rather than to the CAPTCHA-handling URL given in the Authentication for Installed Applications documentation).

AuthSub authorization for web applications

Using AuthSub, users can grant your web application access to their Google Health profile. Both AuthSub and OAuth are the recommend means to connect with Google Health because each token is directly linked to a specific profile in the user's account. Unlike other Google Data APIs, it is required that all requests from your application be digitally signed. This means that you must either use OAuth, or request initial AuthSub tokens with the secure=1 parameter. Using AuthSub with secure=0 tokens is limited to the H9 Developer's Sandbox during development.

Generating the correct AuthSub URL

Both Google Health (/health) and the H9 Developer's Sandbox (/h9) use their own AuthSub handlers. When generating the link to the AuthSub approval page, you can specify a handler by passing its URL as the keyword argument request_url to gdata.service.GenerateAuthSubRequestUrl().

Tip: When beginning development, it's recommended to request an AuthSub token with next=http://localhost and secure=0. If you're ready to test with your own domains, follow the steps in the Domain Registration & Signing Requests of the Getting Started Guide.

The following code generates the correct URL to the H9 AuthSub approval page using secure=0 tokens:

import gdata.service

def GetH9AuthSubUrl():
  next = 'http://localhost'
  scopes = ['https://www.google.com/h9/feeds/']
  session = True
  secure = False
  auth_sub_url = gdata.service.GenerateAuthSubRequestUrl(
      next, scopes, hd='default', secure=secure, session=session,
      request_url='https://www.google.com/h9/authsub')
  
  # permission=0 allows for sending notices.
  # permission=1 allows for sending notices and reading a users profile.
  permission = '1'
  auth_sub_url += '&permission=' + permission

  return auth_sub_url
  
print GetH9AuthSubUrl()

Important: If your application will read data from a user's profile, be sure to include the permission=1 query parameter. See Requesting a single-use token in the protocol guide for details on supported query parameters.

Google Health requires that all API requests be digitally signed, and as a result, the process for generating the AuthSub URL changes slighly if you're requesting secure=1 tokens for either /h9 or /health . You can no longer use http://localhost as the next URL.

The following code generates the correct URL to the Google Health AuthSub approval page using secure=1 tokens:

import gdata.service

def GetHealthAuthSubUrl():
  next = 'http://www.example.com/health.pyc'
  scopes = ['https://www.google.com/health/feeds/']
  session = True
  secure = True
  auth_sub_url = gdata.service.GenerateAuthSubRequestUrl(
      next, scopes, hd='default', secure=secure, session=session,
      request_url='https://www.google.com/health/authsub')

  # permission=0 allows for sending notices.
  # permission=1 allows for sending notices and reading a users profile.
  permission = '1'
  auth_sub_url += '&permission=' + permission

  return auth_sub_url

print GetHealthAuthSubUrl()

Note: Before you can interact with Google Health, you must register your application with Google and Google Health. Please see Domain Registration & Signing Requests in the Getting Started Guide.

Upgrading to a session token

After a successful authorization from AuthSub, the user returns to your next URL with a single-use token appended to the end. For example, http://www.example.com/health.pyc?token=singleUseToken.

The following code demonstrates how to instantiate a service object to use the H9 Sandbox, extract a single-use token from the URL, and upgrade the token to a long-lived session token:

import cgi

parameters = cgi.FieldStorage()
single_use_token = parameters['token']

client = gdata.health.service.HealthService(source='yourCo-yourAppName-v1', use_h9_sandbox=True)
client.auth_token = single_use_token
client.UpgradeToSessionToken()

For /health, the process is slightly different because of the requirement of signed requests.

import gdata.auth

f = open('/path/to/yourRSAPrivateKey.pem')
rsa_key = f.read()
f.close()
current_url = 'http://' + req.hostname + req.unparsed_uri

single_use_token = gdata.auth.extract_auth_sub_token_from_url(current_url, rsa_key=rsa_key)

client = gdata.health.service.HealthService(source='yourCo-yourAppName-v1')
client.UpgradeToSessionToken(token=single_use_token)

It's important to pass in your RSA private key before upgrading the single-use token. After you have a session token, use the UpgradeToSessionToken() method to set the token in the HealthService object. Subsequent API requests will use your private key and session token to sign requests.

For help creating a private key and public certificate, see Creating a self-signing X.509 public certificate in the Getting Started Guide.

Revoking a session token

It's suggested that your application provide users a way to revoke access to their linked profile. The Python client library contains the gdata.service.RevokeAuthSubToken() method for revoking an AuthSub/OAuth token.

The following code revokes the user's session token:

client.RevokeAuthSubToken()

Need more information on authentication?

For detailed information on authenticating to the Google Health service, see these additional resources:

Back to top

Retrieve a list of profiles

Note: This feature is only available (and necessary) when using ClientLogin.

Since ClientLogin requires a profile ID with each of its feeds, applications will want to query the profile/list first in order to select the appropriate profile. The profile list feed returns Atom entries corresponding to each profile in the user's Google Health account. The profile ID is returned in the <atom:content> and the profile name in the <atom:title> element.

To execute a query against the profile/list feed, use the gdata.health.service.GetProfileListFeed() method or construct a gdata.health.service.HealthProfileListQuery():

profile_list_feed = client.GetProfileListFeed()
for entry in profile_list_feed:
  profile_id = entry.GetProfileId()
  profile_name = entry.GetProfileName()
  print '%s, %s' % (profile_name, profile_id)

Retrieve a user's health profile

The profile feed allows you to retrieve a CCR document describing a user's health information. Each profile is encapsulated inside of an Atom <atom:entry>.

The process of extracting data from the profile requires two steps, sending a query and iterating through the resulting feed.

Retrieve a user's CCR data

The following example shows how to query the profile feed and print the CCR for each Atom entry. It assumes the user has authenticated and you have instantiated a HealthService object as client.

profile_feed = client.GetProfileFeed()
for entry in profile_feed.entry:
  print entry.ccr

The gdata.health.HealthProfileQuery class helps simplify constructing a query URL based on the parameters you set. This example queries the user's profile:

query = gdata.health.service.HealthProfileQuery(params={'digest': 'true'})
profile_feed = client.GetProfileFeed(query=query)
entry = profile_feed.entry[0] # we only have one entry with digest=true

Using the digest=true parameter, the user's entire CCR will be consolidated and returned in a single Atom entry.

When using ClientLogin, you'll need to provide a profile id to query:

profile_feed = client.GetProfileFeed(profile_id='12345')

Extracting specific CCR elements

The gdata.health.Ccr class has helpers to extract particular sections of the CCR. You can take advantage of this method by invoking Get<CATEGORY>s, where CATEGORY is one of the supported categories found in the reference guide.

The following snippet builds on the previous examples.

# entry.ccr.GetMedications()
# entry.ccr.GetImmunizations()
# entry.ccr.GetAlerts()
# entry.ccr.GetResults()
# entry.ccr.GetProblems()
# entry.ccr.GetProcedures()

# Example of extracting and printing the names of a user's medications
medications = entry.ccr.GetMedications()
for med in medications:
  name = med.FindChildren('Product')[0].FindChildren('ProductName')[0].FindChildren('Text')[0]
  print name.text

See the CCR reference for more information on elements.

Category Queries

You can also use the HealthProfileQuery to construct queries that return a subset of the user's CCR data, instead of their entire profile. For example, you can construct a query that only returns condition data. See categories in the reference guide for more examples of possible queries.

Example category queries

Only medication data in a single Atom entry:

query = gdata.health.service.HealthProfileQuery(params={'digest': 'true'}, categories=['medication'])
profile_feed = client.GetProfileFeed(query=query)

Medication or condition data in multiple Atom entries:

query = gdata.health.service.HealthProfileQuery(categories=['medication|condition'])
profile_feed = client.GetProfileFeed(query=query)

A more complex query that returns the top 10 medications with 2 items each:

params = {'digest': 'true',
          'grouped': 'true',
          'max-results-group': '10',
          'max-results-in-group': '2'}
query = gdata.health.service.HealthProfileQuery(params=params)
query.categories.append('medication')

profile_feed = client.GetProfileFeed(query=query)

A full list of supported query parameters is available in the query parameters section of the Health API Reference Guide.

Back to top

Sending a notice

Individual posts to the register feed are known as notices. Notices are sent from third-party applications to inform the user of a new event. With AuthSub/OAuth, notices are the single means by which your application can add new CCR information into a user's profile. Notices can contain plain text (including certain XHTML elements), a CCR document, or both. As an example, notices might be sent to remind users to pick up a prescription, or they might contain lab results in the CCR format.

Notices can be sent by calling the gdata.health.service.SendNotice() method.

This example sends a notice to the user's profile using AuthSub:

ccr = '''<ContinuityOfCareRecord xmlns="urn:astm-org:CCR">
  <Body>
   <Problems>
    <Problem>
      <DateTime>
        <Type><Text>Start date</Text></Type>
        <ExactDateTime>2007-04-04T07:00:00Z</ExactDateTime>
      </DateTime>
      <Description>
        <Text>Aortic valve disorders</Text>
        <Code>
          <Value>410.10</Value>
          <CodingSystem>ICD9</CodingSystem>
          <Version>2004</Version>
        </Code>
      </Description>
      <Status><Text>Active</Text></Status>
    </Problem>
  </Problems>
  </Body>
</ContinuityOfCareRecord>'''

created_entry = client.SendNotice('Subject line of your notice', body='Notice <b>body</b>.',
                                  content_type='html', ccr=ccr)
problem = created_entry.ccr.GetProblems()[0].FindChildren('Description')[0].FindChildren('Text')[0]
print "Added the problem '%s' to the user's profile." % (name.text,)

Note: A simple message that does not contain CCR data can be sent using client.SendNotice('Subject line', body='Notice body').

If you're using ClientLogin, be sure to include a profile id:

created_entry = client.SendNotice('Subject line of your notice', body='Notice <b>body</b>.',
                                  content_type='html', ccr=ccr, profile_id='yourProfileID')

Please see the list of supported notice body html elements.

Back to top