HealtheIntent API Workshop
Course Objective
These sessions will teach you how to consume Population Health concepts using the Cerner HealtheIntent APIs.
The HealtheIntent slide deck can be found here.
Prerequisites
For this workshop you will need an HTTP client to call the APIs with. Postman is a popular application that we recommend. Alternatively, you can use an HTTP client library in the language of your choice. Listed below are some of the options you can use. The examples in this workshop will use Ruby’s HTTParty throughout. If you are not familiar with ruby, don’t worry! The ruby quickstart guide will help you get started.
- Postman is the recommended application.
- Advanced Rest Client is also a popular option if you are using Google Chrome.
- You can also use your favorite client in your preferred environment. Some examples include:
Click the Ruby tab at the top of the right column to view Ruby code used to solve each exercise.
Introduction to HealtheIntent APIs
URI Structure
URIs for HealtheIntent APIs generally adhere to one of two structures. The structure used by a specific API can be found in the documentation for that API.
Since HealtheIntent is a multi-tenant platform, both structures include a client mnemonic in the hostname to identify the HealtheIntent client for which API calls are being made.
Most APIs discussed in this workshop use the new platform URI structure, which is:
https://{tenant-mnemonic}.api.us-1.healtheintent.com/{api-name}/{version}
{tenant-mnemonic}=> The tenant mnemonic.{api-name}=> The API name.{version}=> The API version.
For this workshop, we will be using the cernerdemo tenant. So the URI structure will look like:
https://cernerdemo.api.us-1.healtheintent.com/{api-name}/{version}
To make calls to your production tenant, you would replace cernerdemo with your tenant mnemonic.
Authentication and Authorization
HealtheIntent‘s APIs support two different mechanisms for authentication.
- Bearer Token Authentication
- OAuth 1.0a Authentication
For detailed documentation on how to authenticate against the HealtheIntent APIs, please see the documentation we have for Authentication.
Authentication using a Bearer Token
For this workshop bearer token authentication should be used. To create the Authorization header simply take the bearer token value, prefix it with the word Bearer, and place into the Authorization header.
Authorization: Bearer <bearer token value>
The bearer token can be found at tinyurl.com/y9cygfac
For use with ruby, this value can be stored in a variable.
auth_header = 'Bearer <bearer token Value>'
Exercise 1
Create an Authorization header using the bearer token at tinyurl.com/y9cygfac
Note We will be disabling this token at the end of the workshop.
Make the following API call using cURL or Postman to confirm the authorization header is correct:
curl -H 'Authorization: <auth_header>' https://cernerdemo.api.us-1.healtheintent.com/patient/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/a2f6a16d-1331-4ccc-8f70-6c4d953ba70b/demographics
A JSON response body should be returned.
Note The Authorization header created as part of this exercise will be used in the later exercises.
Authorization
The system account we will be using has already been created. It has permissions to access the APIs used in this workshop.
Note We will be disabling this account at the end of this workshop. To request a new system account to pursue further development against our platform, follow the instructions here.
Request Headers
The following headers must be set before you can call the HealtheIntent APIs:
Authorizationmust be set according to the structure of the Authorization header documented here.Acceptmust be set toapplication/json.
Patient APIs
The Cerner longitudinal record is designed to provide a normalized and standardized aggregation of clinical data for a patient. A patient in HealtheIntent represents the demographic information necessary to identify an individual person in the context of a given population. A person in real life may be represented as multiple patients in multiple populations across one or more tenants.
We will be using the cernerdemo tenant mnemonic and following population ID for all of our exercises: 1424e81d-8cea-4d6b-b140-d6630b684a58.
For all exercises, you will need to use the Authorization header created in the authorization exercise.
Patient Lookup
This API retrieves the HealtheIntent patient IDs for a given patient using the local source person IDs and data partition IDs.
Patient ID Lookup API: GET /populations/{populationId}/patient-id-lookup
The Patient API docs can be found here.
Exercise 1
query_parameters = {
'dataPartitionId' => '8dee150d-505f-4635-b009-1bef63d7cf5a',
'sourcePersonId' => '3601867'
}
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/patient/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patient-id-lookup', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response.to_h)
We need to find the HealtheIntent patient ID for Felix K. Dupont. In this case, we’ll assume that 8dee150d-505f-4635-b009-1bef63d7cf5a is the data partition ID for an EMR source and that 3601867 is the person_id from that source.
The unformatted response object is hard to read, so let’s make it look pretty by using pretty_generate!
Click here for the answer
Patient ID for Felix K. Dupont is d4c283a6-1a5c-4427-82ce-ef4ef8e35d30
Click here for the answer
Patient ID for Felix K. Dupont is d4c283a6-1a5c-4427-82ce-ef4ef8e35d30Patient Demographics
We just found the Healtheintent Patient Id for Felix K. Dupont. Now let’s learn a little more about him, by using the Patient Demographics API.
Patient Demographics API: GET /populations/{populationId}/patients/{patientId}/demographics
Exercise 2
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/patient/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/demographics', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Find out Felix K. Dupont’s known addresses.
Click here for the answer
1608 SW SUMMIT VALLEY LN LEES SUMMIT, MO 64081-3781 US
Click here for the answer
1608 SW SUMMIT VALLEY LN LEES SUMMIT, MO 64081-3781 USPatient Medications
Time to check out the medications prescribed to Felix.
Medication API: GET /populations/{populationId}/patients/{patientId}/medications
The Medication API docs can be found here.
Exercise 3
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/medication/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/medications', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Find out all the medications that Felix has been prescribed. What is the most recent medication that Felix has been presribed?
Click here for the answer
Plavix was presribed on Aug 24, 2018.
Click here for the answer
Plavix was presribed on Aug 24, 2018.Patient Allergies
Before we prescribe any new medications to Felix, let’s check out what they have been allergic to.
Allergy API: GET /populations/{populationId}/patients/{patientId}/allergies
The Allergy API docs can be found here.
Exercise 4
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/allergy/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/allergies', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Find out if Felix is allergic to anything.
Click here for the answer
Felix is currently allergic to sulfa drugs. Take note of the status attribute for ‘cancelled’ allergies.
Click here for the answer
Felix is currently allergic to sulfa drugs. Take note of the status attribute for ‘cancelled’ allergies.Patient Conditions
Now it’s time to see all the conditions Felix has. We can use the Condition API to find them.
Condition API: GET /populations/{populationId}/patients/{patientId}/conditions
The Condition API docs can be found here.
Exercise 5
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/condition/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/conditions', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Take a look at all the conditions Felix has. What is the most recently asserted condition for Felix?
Click here for the answer
Diabetes was asserted on Sep 24 2018. It has been asserted multiple time by multiple sources (as have a number of his other conditions).
Click here for the answer
Diabetes was asserted on Sep 24 2018. It has been asserted multiple time by multiple sources (as have a number of his other conditions).Patient Procedures
Let’s check out all the procedures we know about for Felix.
Procedure API: GET /populations/{populationId}/patients/{patientId}/procedures
The Procedure API docs can be found here.
Exercise 6
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/procedure/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/procedures', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Check out all the procedures Felix has undergone. When was his colonoscopy?
Click here for the answer
His colonoscopy was in January 2015.
Click here for the answer
His colonoscopy was in January 2015.Patient Immunizations
Let’s check out all the immunizations we know about for Felix.
Immunization API: GET /populations/{populationId}/patients/{patientId}/immunizations
The Immunization API docs can be found here.
Exercise 7
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/immunization/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/immunizations', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Let’s check out Felix’s immunization record. What immunizations has he had?
Click here for the answer
He has 2 immunizations: Influenza and TDap. Neither have been asserted more than once. He definitely needs to get his seasonal flu shot!
Click here for the answer
He has 2 immunizations: Influenza and TDap. Neither have been asserted more than once. He definitely needs to get his seasonal flu shot!Patient Observations
Let’s check out all the observations we know about for Felix.
Observation API: GET /populations/{populationId}/patients/{patientId}/observations
The Observation API docs can be found here.
Exercise 8
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/observation/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/d4c283a6-1a5c-4427-82ce-ef4ef8e35d30/observations', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Check out what the most recent observation for Felix happens to be.
Click here for the answer
Looks like it is a Height measurement from Sep 24, 2018. Felix is 170 cm tall or about 5’ 6".
Click here for the answer
Looks like it is a Height measurement from Sep 24, 2018. Felix is 170 cm tall or about 5’ 6".Patient Risk Assessments
A risk assessment represents the quantified likelihood of certain outcomes for a patient, for example, the risk of potentially preventable encounters (PPEs) or the likelihood that a patient might suffer from cardiac arrest. In addition to to the type, a risk assessment includes attributes that indicate the method used to inform the assessment and the condition if the assessment pertains to one. Today, the Risk Assessment API only surfaces Risk Assessment generated by the HealtheIntent platform, it does not yet expose Risk Assessments that were sent in from an external source.
Felix doesn’t have any Risk Assessments so let’s switch patients really quick to Joanne Batjes: 106824bb-a35c-4870-97fa-145c7079bc2a.
Risk Assessments API: GET /populations/{populationId}/patients/{patientId}/risk-assessments
The Risk Assessment API docs can be found here.
Exercise 9
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/risk-assessment/v1/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/patients/106824bb-a35c-4870-97fa-145c7079bc2a/risk-assessments', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Find out what type of Risk Assessment Joanna has.
Click here for the answer
A cardiovascular morbidity prediction with a score of ‘2.7’ that wast last calculated Oct 4, 2018.
Click here for the answer
A cardiovascular morbidity prediction with a score of ‘2.7’ that wast last calculated Oct 4, 2018.Bonus Exercise
With Joanne’s patient-id in hand(106824bb-a35c-4870-97fa-145c7079bc2a) go ahead and run through the previous exercises in order to inspect her normalized and standardized aggregation of longitudinal data!
HealtheRegistries
A registry is an aggregation of an organization’s patients who share particular clinical characteristics.
Detailed API documentation for HealtheRegistries can be found here
The HealtheRegistries API uses the legacy URL structure, which can be found here.
Person Registries Summaries
Person Registries summary lets you fetch a person’s registry data using the HealtheIntent person id.
Person Registries summary API: GET api/populations/{population_id}/people/{person_id}/registries
Exercise 1
require 'httparty'
# psssst... remember to create the authorization header
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
MARA risk score is a metric that is used to gauge a patient’s cost of care to the hospital. Average risk score for a person is 1. The cost of care will be more expensive for a patient with a higher risk score.
Tammy Butler’s person_id is 6faf92f6-f3d3-4e0e-b633-48a45df383db, which can be used to fetch her registry. What is the MARA score for Tammy?
Click here for the answer
The MARA score is 0.0
Click here for the answer
The MARA score is 0.0Exercise 2
query_parameters = {fields: 'mara_total_risk_score'}
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response.to_h)
Now using the query parameters filter the response so that you only get the MARA score.
Hint
Use the “fields” query parameter to filter the mara_total_risk_score field.
Hint
Use the “fields” query parameter to filter the mara_total_risk_score field.Exercise 3
query_parameters = { measures_status_filter: 'due' }
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response.to_h)
As Tammy’s primary care provider you want to know all the measures that are due.
Fetch her registry and find out all the measures that are due under Chronic Obstructive Pulmonary Disease.
Hint
Use the “measures_status_filter” query parameter to filter only those measures that are due.
Hint
Use the “measures_status_filter” query parameter to filter only those measures that are due. Click here for the answer
These are the measures that are due are “Influenza vaccination current season”, “spirometry evaluation” and “tobacco use screening and cessation”.
Click here for the answer
These are the measures that are due are “Influenza vaccination current season”, “spirometry evaluation” and “tobacco use screening and cessation”.Person Measure Component Group
Supporting facts for a measure can be fetched using the component group API.
Person Measure Component Group API: GET api/populations/{population_id}/people/{person_id}/registries/{program_id}/measures/{fqn}/componentGroup
fqn is the fully qualified name of the measure (its identifier); an example of this is cernerstandard.adultwellness.org2014.clinical/body-mass-index. Also, program_id is the HealtheIntent program id to which the corresponding measure belongs to; an example of this is cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness.
Exercise 4
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries/cernerdemo.diabetes.org.clinical.cernerdemo-diabetes/measures/cernerstandard.diabetesmellitus.org2014.clinical%2Fbp-less-than-140-80/componentGroup' ,headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Let’s take a look at what Tammy’s last measured blood pressure is. Fetch supporting facts for cernerstandard.diabetesmellitus.org2014.clinical/bp-less-than-140-80 measure from cernerdemo.diabetes.org.clinical.cernerdemo-diabetes program.
Hint
The “/” in the measure needs to be changed to “%2F”.
Hint
The “/” in the measure needs to be changed to “%2F”. Click here for the answer
Blood Pressure 112/60 mmHg.
Click here for the answer
Blood Pressure 112/60 mmHg.Bonus questions
Exercise 5
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/programs', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Retrieve all the programs for the population.
Hint
Need to use the Programs API: “GET api/populations/{population_id}/programs”.
Hint
Need to use the Programs API: “GET api/populations/{population_id}/programs”.Exercise 6
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/programs/cernerdemo.asthma.org.clinical.cernerdemo-asthma-care', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
How many measures does the cernerdemo.asthma.org.clinical.cernerdemo-asthma-care program have?
Hint
Need to use the Programs API: “GET /populations/{population_id}/programs/{program_id}” to retrieve a single program.
Hint
Need to use the Programs API: “GET /populations/{population_id}/programs/{program_id}” to retrieve a single program. Click here for the answer
cernerdemo.asthma.org.clinical.cernerdemo-asthma-care program has 5 measures.
Click here for the answer
cernerdemo.asthma.org.clinical.cernerdemo-asthma-care program has 5 measures.Exercise 7
request_body = { person_ids: ['ae3a2060-1261-43a3-a42b-013b0d700fca', 'a6facde2-b5b3-41e0-b939-3d9c87b258c9', '6faf92f6-f3d3-4e0e-b633-48a45df383db'],
program_ids: [ 'cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness']
}
query_parameters = { measures_status_filter: 'due' }
response = HTTParty.post('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/registries', headers: {'Authorization' => <auth_header>}, body: request_body, query: query_parameters)
puts JSON.pretty_generate(response.to_h)
Stephanie (ae3a2060-1261-43a3-a42b-013b0d700fca), Jason (a6facde2-b5b3-41e0-b939-3d9c87b258c9) and Tammy (6faf92f6-f3d3-4e0e-b633-48a45df383db) are coming in today for a checkup. Fetch their registries and find out what measures are due for their Cerner adult wellness program. The program id for “Cerner adult wellness” is cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness.
Hint
Need to use the Multiple People registries API: “POST /populations/{population_id}/people/registries” to retrieve multiple registries. You will also have to use the “measures_status_filter” query parameter.
Hint
Need to use the Multiple People registries API: “POST /populations/{population_id}/people/registries” to retrieve multiple registries. You will also have to use the “measures_status_filter” query parameter. Click here for the answer
The measures due for Stephanie, Jason, and Tammy are 10, 10, and 7 respectively.
Click here for the answer
The measures due for Stephanie, Jason, and Tammy are 10, 10, and 7 respectively.Hierarchical Condition Categories (HCC)
HCC
Hierarchical Condition Categories (HCCs) are used by Medicare Advantage (MA) plans for reimbursement. The HCC API lets you fetch HCC defined conditions that are persistent from last year and also conditions that are suspected for a person using the HealtheIntent person id.
Detailed API documentation for HCC can be found here
The HCC API uses the legacy URL structure, which can be found here.
Exercise 1
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/hcc_diagnoses', headers: {'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
The HCC Code attribute is composed of the code number and description.
Tammy Butler got her checkup done. Let’s check the code which has a diagnosis code value of J44.9 for Tammy Butler, using her person id from the last exercise (6faf92f6-f3d3-4e0e-b633-48a45df383db).
Hint
Need to use the HCC API: “GET /populations/{population_id}/people/{person_id}/hcc_diagnoses” to retrieve HCC diagnoses data of a person.
Hint
Need to use the HCC API: “GET /populations/{population_id}/people/{person_id}/hcc_diagnoses” to retrieve HCC diagnoses data of a person. Click here for the answer
HCC111 Chronic Obstructive Pulmonary Disease
Click here for the answer
HCC111 Chronic Obstructive Pulmonary DiseaseExercise 2
HCC Data can be of two types. Two types are suspected and persistent. The conditions that are suspected will include a stratification field that categorizes the level of suspicion. The possible values of stratification are NOT SUSPECTED, MODERATELY SUSPECTED and HIGHLY SUSPECTED.
query_parameters = { type: 'suspected' }
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/data_partitions/8dee150d-505f-4635-b009-1bef63d7cf5a/people/3584536/hcc_diagnoses', headers: {'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response.to_h)
Use Tammy’s data_partition_person_id 3584536 and data_partition_id 8dee150d-505f-4635-b009-1bef63d7cf5a to find the stratification value of the code HCC96 Specified Heart Arrhythmias?
Hint
Need to use the HCC API: “GET /populations/{population_id}/data_partitions/{data_partion_id}/people/{data_partition_person_id}/hcc_diagnoses?type=suspected” to retrieve HCC diagnoses suspected data of a person.
Hint
Need to use the HCC API: “GET /populations/{population_id}/data_partitions/{data_partion_id}/people/{data_partition_person_id}/hcc_diagnoses?type=suspected” to retrieve HCC diagnoses suspected data of a person. Click here for the answer
Highly Suspected
Click here for the answer
Highly SuspectedRisk Adjustment Factor (RAF)
Fetches the RAF score data of a person based on population ID and HealtheIntent person ID.
Exercise 3
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/raf_scores', headers: {'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
For Tammy Butler with person ID (faf92f6-f3d3-4e0e-b633-48a45df383db), how many types of RAF scores are present?
Hint
Need to use the RAF_SCORE API: “GET /populations/{population_id}/people/{person_id}/raf_scores” to retrieve Raf scores of a person.
Hint
Need to use the RAF_SCORE API: “GET /populations/{population_id}/people/{person_id}/raf_scores” to retrieve Raf scores of a person. Click here for the answer
4
Click here for the answer
4Exercise 4
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/raf_scores', headers: {'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
For the person ID faf92f6-f3d3-4e0e-b633-48a45df383db, what is the Potential RAF score value?
Click here for the answer
0.322
Click here for the answer
0.322Consumer Portal
Creating a Pagelet for the Consumer Portal
Prerequisites
- Create public GitHub account
- Obtain following information from instructors
- Consumer Portal ID
- Consumer Portal URL
- Login credentials to Consumer Portal
Exercise 1 - Create pagelet HTML
Update the pagelet’s
<html>tag to have ahiddenattribute.
<html hidden lang="en-us">
Include SDK inside the pagelet’s
<head>tag
<script src="https://d3rc9bvtvjyh73.cloudfront.net/healthelife-sdk/healthelife_sdk.js"></script>
Initialize SDK with wildcard ACL for simplicity. It belongs inside the
<body>tag.
<script type="text/javascript">
$HL.App.init({ acls: ['*'] })
</script>
Add CSS to HTML for pagelet loading and embedding to the
<style>tag at the top of the document.
/* Hide pagelet until loaded by trusted page */
html[hidden] {
display: none;
visibility: hidden;
}
/* Prevent bars and clipping. */
html, body {
overflow: hidden;
margin: 0px;
padding: 0px;
}
/* Allow proper sizing of pagelets in sdk, even if they have float components */
body:after {
content: "";
display: block;
height: 0;
clear: both;
}
A pagelet is a web page embedded into the Consumer Portal. It needs to be deployed and available to your users on the internet. For simplicity of this exercise, we will be using GitHub’s Pages functionality that provides an easy way to host web pages. You create an HTML file in a GitHub project and Github will host the file at a dedicated URL. In a real pagelet, you would deploy your pagelet to your own servers and manage them that way.
NOTE: GitHub Pages sites have a limit of 10 builds per hour. If your page isn’t updating, this could be the reason.
- Fork chc2018-pagelet-exercise project on Github
- Navigate to
https://<your-gh-username>.github.io/chc2018-pagelet-exerciseto verify pagelet exists - Update the
index.htmlfile in the project using the Github UI. NOTE: The code changes appear to the right in this documentation.- Click the pencil icon to enter Edit mode
- Update the pagelet’s
<h1>tag to contain your name - Update the pagelet’s
<html>tag to have ahiddenattribute.- This is done so that the contents do not appear until the pagelet authorizes the Consumer Portal is in its ACL list.
- Include SDK inside the pagelet’s
<head>tag - Initialize SDK with wildcard ACL for simplicity. It belongs inside the
<body>tag. - Add CSS to HTML for pagelet loading and embedding to the
<style>tag at the top of the document. - Click the “Commit changes” button
- Navigate to
https://<your-gh-username>.github.io/chc2018-pagelet-exerciseto verify changes have been applied. You should see your name on the page now.
Exercise 2 - Display pagelet in portal
Your new pagelet is now ready for display in the Consumer Portal. Currently, the only way to display your pagelet is to work with your Cerner support team to update your portal configuration. We will eventually have a way for you as an administrator to configure the Consumer Portal to display the pagelet. For the purposes of this exercise, we have created a workaround for you to display your pagelet in the Consumer Portal without updating any configuration. Follow the steps below to display the pagelet.
- Using the Consumer Portal URL and credentials given to you in the prerequisites, login to the Consumer Portal.
- You should see a page that allows you to enter a URL and display your pagelet in the portal.
- Enter your pagelet URL (
https://<your-gh-username>.github.io/chc2018-pagelet-exercise) in the text box - Click the “Open Pagelet” button
- Your pagelet should now appear on the page.
Exercise 3 - Scroll into view
Let’s explore some more functionality that the HealtheLife SDK provides for pagelets. Sometimes a pagelet is quite long and there are actions in the pagelet that require the user to jump back to the top of the pagelet. The SDK provides a scrollIntoView() method for this. This exercise will show you how to use this functionality.
- Go back to your Consumer Portal URL used in the previous exercise to open your pagelet.
- Enter this pagelet URL from your GitHub Pages -
https://<your-gh-username>.github.io/chc2018-pagelet-exercise/scrollIntoViewand click the “Open Pagelet” button. - At the very bottom of the page is a “Scroll to Top” button. It currently does nothing if you click it. We will change the click behavior so that it will scroll the pagelet back to top of the iFrame.
- Edit the
scrollIntoView.htmlfile in your GitHub repo using the UI. - Modify the button to have an “onclick” handler as follows:
<button class="btn" onclick="$HL.App.scrollIntoView()">Scroll to Top</button>
- Commit your changes to the file.
- Repeat steps 1 - 2
- Scroll down and click the “Scroll to Top” button. It should take you back to the top of pagelet.
Exercise 4 - Navigate to new route
Another thing a pagelet may want to do is route the user to another page in the portal. The SDK provides a routeTo() method for this. This exercise will show you how to use this functionality. We will take the pagelet created in exercise 1 and enhance it to route you to the dashboard of the Consumer Portal.
- Edit the
index.htmlfile in your GitHub repo using the UI. - Go back to your Consumer Portal URL used in the previous exercise to open your pagelet.
- Add a button that will perform this routing with the following code inside the pagelet’s
<body>tag:
<button class="btn" onclick="$HL.App.routeTo({path: '/pages/home'})">Go to Dashboard</button>
- Commit your changes to the file.
- Go back to your Consumer Portal URL used in the previous exercise to open your pagelet.
- Enter your original pagelet URL from exercise 1 & 2 (
https://<your-gh-username>.github.io/chc2018-pagelet-exercise) and click the “Open Pagelet” button. - Click the new “Go to Dashboard” button you just added
- You should be routed to the Consumer Portal dashboard
Data Syndication
Data syndication facilitates the bulk delivery of HealtheIntent data. It provides direct, low-level, asynchronous access to the information that HealtheIntent solutions create, curate, and operate against. This API is used mainly to populate a data warehouse or other third-party data store for research, reporting, or analytical activities.
The Data Syndication API docs can be found here.
Terminology
| Term | Definition |
|---|---|
| Feed types | The types of available data sets, for example, Longitudinal Record. |
| Feeds | The set of data that you want to receive on a schedule, for example, Longitudinal Record for population ABC. |
| Bundles | The output of a feed, for example, Changes to the Longitudinal Record for population ABC between 2018-04-01 and 2018-04-02. |
| Channel Types | The ways you can have bundles delivered. Currently, the only supported mechanism is download, which makes the data available as archive files you can download using this API. Support for other mechanisms is planned. |
| Channels | Specifies that you want to receive a feed’s bundles using a particular channel type and provides any necessary configuration for the channel type. For example, a channel could specify that you want to receive your Longitudinal Record for Population ABC feed using the download channel type. |
| Deliveries | The status of delivering a particular bundle using a particular channel. For example, you would use the Deliveries endpoint to determine whether the archive file for changes to the Longitudinal Record for population ABC between 2018-04-01 and 2018-04-02 bundle is available for you to download. |
To help understand these concepts, consider an analogy to the delivery of physical products. Suppose you want to have a newspaper, the Cerner Post, delivered to you by the postal service every day, but that you are only interested in the classifieds section. In this example:
- The feed type is the Cerner Post.
- The feed specifies that you want to receive only the classifieds section, and that you want the newspaper every day.
- Every day a bundle is generated containing the classifieds section for that day.
- The channel type is the postal service.
- The delivery channel contains everything the postal service needs in order to deliver to you, for example, your name and address.
- Every day a delivery happens when the postal service delivers the bundle to your mailbox.
Find New Bundle
For this series of exercises, we will check for and then download the newest bundle in our feed.
Exercise 1
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/syndication/v1/feeds/', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Normally, your Feed ID and Channel ID will be given to you when they are set up. But for now, let’s pretend that they were not. You can use the /feeds endpoint to search for the feeds associated with your tenant. Find the Feed ID for the Longitudinal Record, Cerner Demo Population feed.
Click here for the answer
The Longitudinal Record feed for the Cernerdemo tenant is: a7d5f3cc-ff2c-44cb-a95e-23a08510d469
Click here for the answer
The Longitudinal Record feed for the Cernerdemo tenant is: a7d5f3cc-ff2c-44cb-a95e-23a08510d469Exercise 2
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/syndication/v1/channels?feedId=a7d5f3cc-ff2c-44cb-a95e-23a08510d469', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Again, normally you would be given your Channel ID, but for fun, let’s use the API to find it instead. You can use the /channels endpoint to find channels.
Click here for a hint.
You can filter the channels by feedId, which we have from Exercise 1.
Click here for a hint.
You can filter the channels by feedId, which we have from Exercise 1. Click here for the answer.
Channel ID: 57e55d2e-3865-4f82-9f6b-f4f58d430338
Click here for the answer.
Channel ID: 57e55d2e-3865-4f82-9f6b-f4f58d430338Exercise 3
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/syndication/v1/feeds/a7d5f3cc-ff2c-44cb-a95e-23a08510d469/bundles', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
Now that we have the Feed ID and the Channel ID, the next thing we’ll need to do is find the most recent bundle.
Click here for the answer
As of 10/7/18, BundleID 54486dfb-824f-47be-be6b-d0d159c9892f is the latest.
Click here for the answer
As of 10/7/18, BundleID 54486dfb-824f-47be-be6b-d0d159c9892f is the latest.Find Delivery ID
Now that we know the latest bundle, we need to find the Delivery ID, as that is what will be used to download the bundle.
Exercise 4
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/syndication/v1/channels/57e55d2e-3865-4f82-9f6b-f4f58d430338/deliveries?bundleReleasedAfter=2018-10-06T00:00:00.000Z', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response.to_h)
What is the latest delivery as of 10/7/18?
Click here for the answer.
Latest Delivery as of 10/7/18: 1bd910a9-9e5c-4eba-90e4-b6aabd5b9242
Click here for the answer.
Latest Delivery as of 10/7/18: 1bd910a9-9e5c-4eba-90e4-b6aabd5b9242Download Delivery
With the Delivery ID, we will be able to download the latest bundle.
response = HTTParty.get('https://cernerdemo.api.us-1.healtheintent.com/syndication/v1/downloads/86a339c3-bb6b-4c4b-b8e4-b66aa42f5f64', headers: {'Accept' => 'application/octet-stream', 'Authorization' => <auth_header>})
File.binwrite('bundle.tar.gz', response.body)
Note: Given the nature of the Data Syndication API, the bundles can be quite large (10’s or 100’s of gigabytes). Therefore, we ask that you do NOT actually download the bundles over the wifi for bandwidth’s sake.
