http://www.developer.com/

Back to article

Creating a Cloud Client with Adobe AIR, JavaScript, and Google Health


October 28, 2009

Personal health information management is closely related to a concept that has been in the U.S. media a lot recently, EHR (Electronic Health Records). Leaving behind the long, convoluted history of EHR both in the US and abroad, suffice it to say that there is a significant governmental push for widespread adoption of this type of technology in healthcare. (See "Health Records in the Cloud" for a further discussion of this issue.)

Both Google and Microsoft offer cloud-based solutions for personal health information management: Google Health and HealthVault, respectively. They provide some of the necessary infrastructure for enabling large-scale adoption of EHR, but the vendors differ in their approaches. For instance, Google Health and HealthVault differ in certain aspects (click here for a detailed comparison), and Microsoft now offers a full range of healthcare and life sciences software (Microsoft Amalga).

This article demonstrates how to develop a simple AIR/JavaScript client to Google Health. I chose Google Health simply because it is the first of the two services that I've had a chance to explore. I chose Adobe AIR for few reasons:

  • platform independence
  • the potential to run on mobile devices (thus, enabling the vision outlined in the beginning of the article)
  • intuitive support for database storage (which is an important component of the application architecture)

Also, because the Google documentation and SDK do not include JavaScript (the online samples and SDK cover Java, .NET, PHP, and Python), I had the chance to create something new.

The Application

To use the demo application, you will need a Google account. You will use the account to link to Google Health (creating a health account and authorizing the storage of personal data in the process). For the purposes of this article, I created a fictitious account for Vincent van Gogh: pvvgogh.ghdemo@gmail.com, password vincentvan. You can create your own, but I advise against using your real account to store demo data.

Google Health provides a sandbox environment for testing purposes. The only difference between the sandbox and the real application environment is that the sandbox is referenced using h9 instead of health (i.e., www.google.com/h9). All references in code point to h9 as well (this is documented in the code download).

Notice that you can enter/view data using the Google Health GUI. The application described here replicates the same functionality on a smaller scale. Notice also that you can associate another person's data to your account. That is, you can store his or her data alongside yours. This is a handy feature, perhaps targeted at a parent who will enter and maintain the health data for the entire family. Again, for scope purposes, the application discussed here will allow access to only the primary account data. However, comments in the code show where this limitation is located, and enabling access to all associated accounts is rather trivial.

The Google Health account includes the following types of details:

  • Demographics
  • Conditions
  • Medications
  • Allergies
  • Procedures
  • Test results
  • Immunizations
  • Insurance

It can also store images (of any kind, but the intent is to store scanned documents or copies of CTI/MRI scans) with one important caveat: medical images tend to be very large. How effective Google Health can be at storing medical images in a real use scenario remains to be seen.

Very importantly, Google Health allows physicians' offices to access and update this data, and Google is negotiating access protocols with a variety of healthcare providers. A list of current medical providers with integrated access to Google Health is available here.

One interesting Google Health feature is the ability to detect possible adverse interactions between drugs. As stated in the Google Health Help section: “When you're adding medications to your profile, you may see a warning symbol (either a hexagon or a triangle with an exclamation point) beside the Drug interactions link on the left side of the page. You can click this link to see potential drug interactions, including interactions among drugs, diseases, and allergies.”

The demo application will allow a user to authenticate to the account, read data stored in the account, and post (some) data. Because there is a huge variety in the data that a user can post, I have included only a couple of templates (for conditions and medications). Posting other types of data will be similar.

The Architecture

The demo application is a forms-based, single-user desktop application. The client will connect to the cloud using the ClientLogin API. (The cloud as defined in this article is an online service storing data that developers can access via a set of API's. Data storage is abstracted to the user, who has to relinquish a certain amount of control over it, but who ultimately owns the data and has full access control.)

ClientLogin is one of the two Google Data APIs for authenticating to various Google services. The other is the OAuth API. Desktop/installed applications use ClientLogin, while web applications use OAuth. The two have other differences, for example, in the types of operations allowed under each API. More details will follow, and you can click here for a comparison of ClientLogin and OAuth.

When the client connects to the cloud, it will allow the user to read the data—either the full profile or the specific data components previously listed (conditions, medications, allergies, etc.). Google Health will return the data as an XML/Atom stream, which the client will render as received. A production-level application will certainly have to display this data in a more user-friendly format (as noted earlier, however, I focused this demo on the aspects that deal with the communication with the service to keep the size of the code manageable).

You add data to the service by using several template forms. When the user chooses to upload condition data, for example, a conditions form opens with a few fields specific to the Continuity of Care Record (CCR) conditions definition. The CCR specification is potentially large, so you will have to decide which fields you want to build support for. (See "CCR and Health-Care Technology Standards" for a further discussion of the CCR spec.)

When the data has been posted, you can view it in the application or use the Google Health GUI itself (but you will have to refresh it in the browser). Attempting to post the same data twice results in an error, because the protocol requires a different approach for updating data (a further discussion on this shortly).

I used the Aptana Ruby on Rails IDE (with the AIR plugins) to develop the application and manage the source files. I used the SQLite 2009Pro application to manage the SQLite database. The latter has been especially useful when dealing with XML data. For a production application, you probably should use an ETL tool such as Microsoft SQL Server Integration Services, but for this demo, SQLite 2009Pro is more than adequate.

Figure 1 shows the files included in the demo application.


Figure 1. Files in Demo Application: These are all the files included in the Google Health demo application.

The HTML files are the actual HTML forms that make up the GUI of the application. The AIR environment will load them at run time to populate the native AIR windows. GH_Condition and GH_Medication are the HTML forms used to upload the conditions and medications, respectively. As previously mentioned, their fields correspond to the XML feeds stored in the database (also included in the templates directory). The code for each form is in the corresponding *Codebehind JavaScript file, with some global functions and classes in the application.js file. Application.xml is the AIR application descriptor.

The application uses a local database to store authentication information and to store some post template information.

The Database

The database backend of the demo application is SQLite, which is natively supported by the AIR environment. The database, GoogleHealthAir.db, is included in the source code for this article. It should reside in the Documents folder of the user running the application. It includes only three tables:
  • VariablesVariableName VARCHAR(50), Variable Value VARCHAR(50)—includes session data such as login, password, the authorization token returned by Google Health, and the profile ID of the main profile of the account.
  • TemplatesTemplateType VARCHAR(50), Xml TEXT, HTMLFilePath VARCHAR(50)—includes the templates used to post data. Only two templates are included here, one for medication data and the other for condition data. The HTMLFilePath field points to the HTML form that the application uses to collect the data it will post. The Xml field contains the XML feed (with a subset of the CCR data corresponding to the fields available on the HTML form) that has to be posted to the service, with placeholders in lieu of actual data. You have to be very careful with this XML feed. You can easily make a small mistake that will cause the service to reject the feed. The Google Health documentation offers feed samples online.
  • ConditionsDescription VARCHAR(50), ICD9 VARCHAR(10)—are ailments, diseases, etc., that the healthcare profession handles, and it has a comprehensive standardized record of conditions, the ICD9 international standard. Basically, every medical condition has an identifying code associated with it. I added only two conditions to my table, but you could download the entire standard and load it into the table. Perhaps a better solution would be to create a web service that returns a condition identified by its code, the code for a specific condition, or a subset of conditions starting with a certain letter, etc. The Google Health GUI does a nice job of "intelli-sensing" conditions as you type the name.

The Details

The entry point into the application is the GH_Main form. Clicking the Connect button saves the password and login that the user types in the local database (after truncating the Variables table) and opens the GH_Choose form. Here, the user has the option to view or add data to a profile.

Things start to get interesting in the onLoad event handler of the form (implemented in the doLoad function in the ChooseCodebehind.js file). Here, a XMLHttpRequest is posted to ClientLogin to get an authorization token that will be used to send further requests. When the authorization token is received, the application queries the service for the profiles associated with the account. (Remember, you can add several profiles' data to the main account.)

The application does this by posting a GET request to https://www.google.com/health/feeds/profile/list with a GoogleLogin auth parameter set to the authorization token received. The response is a XML stream from which the coded identifier for the profile has to be extracted (implemented in the process function in the application.js file). When extracted, the identifier is saved in the Variables table too, as it will be used for further requests.

Reading Data

At this point, you have all that you need to read or write data. Reading is simpler; you can start with the GH_ReadData form. From here, the user can access the entire profile feed or query for specific “categories” such as medications, conditions, immunizations, allergies, procedures, results, insurance, and demographics data.

The entire profile query (implemented in the getProfile function) sends a GET request to the https://www.google.com/health/feeds/register/ui/profileid service, where profileid is the code for the profile retrieved earlier. The authorization token must also be provided in the request. The service will return all the data associated with the profile, as CCR-compliant information. The request endpoints will differ depending on whether you use ClientLogin or OAuth as your authentication API.

To read specific categories, you need to send another GET request to https://www.google.com/health/feeds/register/ui/profileid with a special format. Basically, the address where the request is sent must also include a pointer to the specific category (e.g., “/-/medication”). The format can be more complex and it can include querying for several types of categories, requesting a limited number of responses, etc. (the complete query syntax is available here). In both cases, the response will be an XML/Atom feed, which you will need to parse to extract the interesting data.

Writing Data

Writing data is more complex because of the payload that you must send with the requests. As mentioned previously, the process for adding data uses the GH_AddData form as a shell from which to launch forms specific to each category being written (medications, conditions, etc.). For example, for the “conditions” category (one of the two categories implemented in this demo), clicking the Add Item button will result in the code-behind GH_AddData launching the GH_Condition form. This form has its own event handlers, implemented in the ConditionCodebehind.js file. When the form is loaded, the (very limited range of) conditions dropdown box is populated from the database. The doPost function performs the actual posting of a new condition notice by reading the formatted XML post feed from the database and populating it with the data entered by the user from the screen.

To add a new notice, a POST request must be sent to https://www.google.com/health/feeds/register/ui/profileid. The XML feed is the actual message to be posted, and this action is performed by the postNotice function in the application.js file.

Updating an Entry

Updating an existing entry is possible only when ClientLogin is used to authenticate. OAuth allows for only new entries to be inserted. A PUT request has to be sent to https://www.google.com//health/feeds/register/ui/profileID/entryID, where entryID identifies the profile element to be updated. The GH_Medication form and MedicationCodebehind.js file implement the same functionality for the medication category.

All of the above seems (and is) very straightforward, but getting all the needed information together is not as simple as it should be, given the way the Google documentation is organized and the size of some of the samples provided.

An Early Exploration into an Emerging Field

Google Health's somewhat confusing documentation and its limited range of examples, sample code, and SDKs show that this is indeed an evolving product. I suspect that the current range of potential applications is relatively narrow, but it seems likely that the platform will grow and its adoption will generate much more developer interest in the future. A potentially interesting development is in the area of medical devices, which could be made to interact directly with the service (something that Microsoft is already offering).

The potential of the service notwithstanding, I think the programming model and the concept demonstrated in the demo here are very useful, as you can expect similar services in various industry verticals to emerge in the future. AIR proves to be a versatile tool, capable of handling the client side of this type of distributed applications with sufficient ease and power. Learning to leverage it within a cloud type of application scenario might be something more developers wish to do.

Code Download

  • GoogleHealthAir_src
  • For Further Reading

  • "Microsoft HealthVault is nothing like Google Health" (from ZDNet)
  • Continuity of Care Record (CCR) Standard — Resource Site
  • IHE.net Homepage
  • Google Health Partner Profiles
  • Learning More About Your Health: Drug interactions (from Google Health)
  • ClientLogin for Installed Applications (from Google Code)
  • Google Data APIs Authentication Overview (from Google Code)
  • International Statistical Classification of Diseases and Related Health Problems (from Wikipedia)
  • Online ICD9/ICD9CM Codes
  • RAVEN Software Minimum Data Sets 2.0
  • Health Query Parameters Reference (from Google Health Data API Reference Guide)
  • About the Author

    Razvan Julian Petrescu is a developer with a background in healthcare. The difficulties he encountered when trying to have eye examination records transferred to another optometrist are the inspiration behind this article. Reach him at razvan.petrescu@gmail.com.

    Sitemap | Contact Us

    Thanks for your registration, follow us on our social networks to keep up-to-date