This tutorial will introduce you to launching a SMART on FHIR app from a the logica Sandbox.
The codebase you will use contains a basic client-side SMART on FHIR web application that uses the client-js
javascript SMART on FHIR client library. Although the provided app mearly displays the retrieved FHIR resources, you can easily use it as a framework for developing a more interesting tool.
This tutorial is based on this excellent tutorial made by the Cerner engineering team. If you work with Cerner, feel free to check out their tutorial as well!
- 1. Overview
- 2. Table of Contents
- 3. Prereqs
- 4. Learning Objectives
- 5. First Steps
- 6. Explore the Project Folder
- 7. Setup Github Pages
- 8. Register Your App
- 9. Launch Your App
- 10. Authorize Your App
- 11. Get Patient Data using FHIR
- 12. Test Your Application!
- 13. Extra Credit
- 14. Next Steps
-
Create a public GitHub account if you do not have one by going to www.github.com and clicking the
Sign up for Github
button. -
Create an account for the logica Sandbox by going to https://sandbox.logicahealth.org/#/start and clicking the
Register
button. -
Install a text editor for viewing and editing code. Some options:
-
Install Git if you don't have it. Check out the Git book install guide and the download page Note: if you're unfamiliar with git or Github, check these out:
- Create and Register a SMART on FHIR App in the logica sandbox.
- Launch app as a patient and as a provider from the logica sandbox using the SMART on FHIR Javascript Client.
- Demonstrate interoperability by launching app from SMART on FHIR sandbox.
- Set up a standalone patient access app.
- Build on the provided code to make something useful!
-
Fork the SMART on FHIR app from Github.
- Create an account on Github if you have not already.
- Log in to your Github account.
- Navigate to https://github.com/uw-fhir/smart-on-fhir-tutorial.git.
- Click on the
Fork
button in the top right corner of the page. - Wait a few seconds, and you should see a copy of the repo in your github account.
-
Clone your project to your computer.
- Open a terminal or Git Bash.
- Navigate to a folder where you want to keep your project. For example:
cd C:/Users/Piotr/code
. - Find the project url by clicking the green
Code
button on your Github project page and copying it to your clipboard. - Run the following command in the terminal to clone this project into the chosen folder:
git clone https://github.com/[YOUR-USER-NAME]/smart-on-fhir-tutorial.git
. - When you open your chosen folder, you should see the project files in a directory called
smart-on-fhir-tutorial
. - Make sure you're working off of the
gh-pages
branch by runninggit checkout gh-pages
. You should get confirmation that you are on thegh-pages
branch.
- Open your project folder in your text editor for this tutorial to be able to view and change the files. We'll be using VS Code; so if you're also using that editor, go to
File/Open Folder...
to accomplish this.
Take a minute or two to explore the codebase. Here are some highlights:
-
example-smart-app
: This directory contains a simple client-side web application. -
example-smart-app/lib/js/fhir-client.js
: The app uses uses the library to (1) communicate with our Sandbox using the FHIR API and (2) handle the SMART on FHIR authorization workflows. Check out more information about this client here: https://github.com/smart-on-fhir/client-js. -
example-smart-app/launch.html
: this webpage is the initial entry point into the SMART on FHIR application, called thelaunch_url
in the SMART documentation. This page will be called by the logica sandbox when we launch our app. We'll cover the different launch patterns later in the tutorial. -
example-smart-app/launch-smart-sandbox.html
: this page is similar to the previous launch, but will be used when we launch from the SMART on FHIR sandbox. -
example-smart-app/launch-standalone.html
: this page is similar to the previous launch, but will demonstrate launching a stand-alone application - in this case from a patient context. -
example-smart-app/index.html
: this is the main web page for our application, and will be redirected to after Authorization succeeds.
You will be using Github Pages as an easy way to host our app. Github pages can be used for static or client-side web applications. Your forked repo should have github pages set up, but you need to push an update to the code in order for them to be published. This is what you'll do in this step.
-
Edit
example-smart-app/index.html
- Open the target file in your text editor.
- In the
<head>
section, find the<title>
tag and replace the text inside with something like:<title>[Your Name]'s SMART App</title>
.
-
Commit and Push your change
- Open your terminal or Github Bash window
- Navigate to the project folder:
cd [path-to-project-folder]
- Stage all of your changes:
git add .
- Commit your changes and write a commit message describing your work:
git commit -m "[some commit message]"
-
Test out your app
- Go to
https://<your-github-username>.github.io/smart-on-fhir-tutorial/example-smart-app/health
. - If you see a thumbs-up, good job!
- Go to
In order for us to be able to launch our app from the HSCP Sandbox and access the FHIR resources, we need to register our app with the sandbox.
-
Setup the logica Sandbox.
- Go to the logica sandbox site.
- Sign in with the logica account you should have made already :)
- Select the "Create Sandbox" button on the bottom of the left column.
- Name your Sandbox something cool (or just UW FHIR WORKSHOP).
- Select Sandbox Version "FHIR STU 3 (v3.0.1)".
- Make sure the "Allow Open FHIR Endpoint" option is selected ("Import sample patients and practitioners" and "Import sample applications" options are optional).
- Add a description if you'd like. (i.e. This is for the UW FHIR Tutorial).
- Click the
Create Sandbox
button.
-
Setup your Application.
- Click your newly created sandbox on the main dashboard.
- Select
Apps
on the left hand side. - Click the
+
button and selectManually
- Fill out the following form fields:
- App Name: Anything your imagination desires!
- App Type:
Public Client
- App Launch URI: https://<your-github-username>.github.io/smart-on-fhir-tutorial/example-smart-app/launch.html
- Redirect URI: https://<your-github-username>.github.io/smart-on-fhir-tutorial/example-smart-app/
- Allow Offline Access: Unchecked
- Patient Scoped App: Unchecked
- Note and jot down the
App Client Id
from the popup that should show up on your screen.
We'll talk about what some of these configuration options mean later in the tutorial, but for now, congrats! Your app is now registered! You should see it show up on your Sandbox Dashboard.
SMART on FHIR apps can be launched in a variety of ways. You can browse http://docs.smarthealthit.org/authorization/#ehr-launch-sequence and http://docs.smarthealthit.org/authorization/scopes-and-launch-context/#scopes-for-requesting-context-data for more information, but we'll present a quick summary.
The SMART standard provides aims to provide an "App Platform for Healthcare", and as a result SMART on FHIR defines a couple of different launch patterns based on four use cases defined by the Argonaut Project. You'll try out two of these in the main tutorial, and another one in the Extra Credit section. These are the scenarios you'll focus on:
-
A Provider-facing EHR Launch: This type of launch would happen from inside of a provider-facing EHR UI. For example, a provider might be examining a patient's chart in Epic Hyperspace, and click a link on the chart to launch this application in the current EHR context.
-
A Patient Portal Launch: This type of launch would be initiated by a Patient from a patient-facing EHR portal like Epic MyChart. A patient would be logged into their portal, and click a link or button that would launch this app in their Patient context.
-
A stand-alone app is launched externally by either a patient or provider, but uses SMART on FHIR to authorize with the EHR and access relevant data using FHIR resources. You'll see this type of launch in the extra credit section if you're the ambitious type =)
You'll create scenarios for the first two types of launches in the logica sandbox. Click here for more detail.
First, we need to create a couple of personas for the providers and patients that we will be simulating in this scenario:
- Click the
Personas
link on the left side of your sandbox dashboard.
You'll create or select one provider persona by clicking the darker blue Practitioner
button and one patient persona by clicking the lighter blue Patient
button. Follow these steps for each:
-
Click the appropriate button.
-
Find or create an interesting patient or provider you'd like to use and click on them. Note: If you would like to create a patient or provider, navigate to the
Practitioners
andPatients
sections on the lefthand side. Clicking on a patient will allow you to dive deeper into the patients and their associated resources. -
Chose any user id and password and jot them down.
Now on to the scenarios, which you'll build two of.
-
Click the
Launch Scenarios
link on the left side of your sandbox dashboard. -
Click the
+
button on the right side of the dashboard. -
Select your app
-
Choose your provider persona for one scenario, and patient persona for the 2nd.
For the provider scenario, you'll need to provide the patient context. In the Additional launch context
screen:
- Find your patient by name using the search function and select them.
If you did most things right, you should see two new launch scenarios listed on the Launch Scenario
dashboard. Yay!
The EHR or Patient Portal sends request to launch.html
with the following parameters:
iss
: Identifies the EHR's FHIR endpoint, which the app can use to obtain additional details about the EHR, including its authorization URL.launch
: Identifies this specific launch and the associated EHR context. This identifier has to be communicated back to the EHR with the authorization request.
The SMART on FHIR javascript client library (fhir-client.js
) takes care of all of the heavy lifting. This bit of code makes our job pretty easy. All we have to do is call FHIR.oauth2.authorize()
and supply the client_id
generated by the code console during registration and the scopes we registered.
Now that we have our launch scenarios created and app registered, let's talk about how SMART apps authorize with the EHR Authorization Server.
source: http://www.hl7.org/fhir/smart-app-launch/-
Your app accesses the conformance statement using the server url sent with the
iss
parameter and recieves an url for the authorization server. -
Your app sends a request to the authorization server that includes a couple of parameters that you can look over here: http://docs.smarthealthit.org/authorization/#1-app-asks-for-authorization.
-
If authorization succeeds, the App receives an authorization code from the authorization server.
-
The app exchanges this code for an access token by sending a request back to the server.
-
This access token is stored by the app and used to retrieve protected FHIR resources allowed by the scopes.
The index.html
file includes a script which calls into the extractData()
function in example-smart-app.js
. extractData()
uses the FHIR.oauth2.ready()
function to exchange the authorization code for the access token and stores it in session storage for later use.
Again of these exchanges are facilitated by fhir-client.js
- which is much easier for us!
http://docs.smarthealthit.org/authorization/scopes-and-launch-context/
launch.html
is configured by default with a very basic set of scopes. For now, leave this set of scopes as is, but make sure to update your app registration to match:
- In the logica Sandbox - App Dashboard, over over your app and click on the settings button on your app's tile.
- Fill out the
Scopes
section with the same contents as thescope
field in launch.html
We now have a valid access token, and can use it to send requests to the FHIR endpoint to retrieve our patient's data. See http://docs.smarthealthit.org/authorization/#4-app-accesses-clinical-data-via-fhir-api.
We will depend on the fhir-client.js
library to retrieve these resources using a couple of the available APIs:
smart.patient.read()
: This returns the context for the patient the app was launched for.smart.patient.api.fetchAll()
: This will use the fhir.js API to retrieve a complete set of resources for the patient in context.smart.byCodes()
: A utility function that returns a function to search a given resource for specific codes returned from that response.
Here's the relevant code in example-smart-app.js
:
// Starts at Line 12
var patient = smart.patient;
var pt = patient.read();
var obv = smart.patient.api.fetchAll({
type: 'Observation',
query: {
code: {
$or: ['http://loinc.org|8302-2', 'http://loinc.org|8462-4',
'http://loinc.org|8480-6', 'http://loinc.org|2085-9',
'http://loinc.org|2089-1', 'http://loinc.org|55284-4']
}
}
});
...
$.when(pt, obv).done(function(patient, obv) {
var byCodes = smart.byCodes(obv, 'code');
...
We'll walk through the code first, and then modify it to retrieve the data you require for your specific patient.
As an aside, the fhir-client.js
library defines several more API’s that will come in handy while developing smart app. Check them out here: http://docs.smarthealthit.org/clients/javascript/.
-
Open up the
Patient Data Manager
for the patient you chose for you scenarios and click on theObservation
tab in the left column. -
Find an observation or set of observations that you'd like to access and display in your app and note their observation codes.
-
Update the FHIR query in
example-smart-app.js
to match this code or list of codes by updating the following section:query: { code: { $or: [ "http://loinc.org|8302-2", "http://loinc.org|8462-4", "http://loinc.org|8480-6", "http://loinc.org|2085-9", "http://loinc.org|2089-1", "http://loinc.org|55284-4" ]; } }
-
Check if your Observation(s) are being correctly fetched by updating this code block with the codes you're using and inspecting the output in the Chrome javascript console:
console.log("byCodes:"); console.log(byCodes("8480-6")); console.log(byCodes("8462-4"));
-
Read and parse the fetched Observation(s) to access their values and units by modifying the following code block:
// Observations yourObservation = byCodes("<your-observation-loinc-code>");
-
Modify the layout of
index.html
and thedeafault_patient()
function to display your observation values:function defaultPatient(){ return { fname: {value: ''}, lname: {value: ''}, gender: {value: ''}, birthdate: {value: ''}, <new-label-for-your-observation>: {value: ''} }; }
<h2>Observation Resource</h2> <table> <tr> <th>[readable-text-describing-your-observation]</th> <td id='<new-label-for-your-observation>'></td> </tr> </table>
-
Add a new attribute to the patient object
p
that is used to update theindex.html
page content by modifying the following code block:// Observations p.<new-label-for-your-observation> = getQuantityValueAndUnit(yourObservation[0]);
-
Inspect the patient object
p
in the Chrome javascript console to make sure the data is showing up correctly.
- Go to
Launch Scenarios
and launch using the corresponding scenario.
- Go to
Launch Scenarios
and launch using the corresponding scenario.
- Go to
Launch Scenarios
and click on the row of the scenario you want to launch in the EHR simulator - Click the
Launch Embedded
checkbox - Launch the Scenario!
- Click on the
EHR Simulator
in the left-hand column. - Select a provider and patient for the context of your EHR session.
- Click on your app's tile to launch the app inside the EHR session.
A major goal of SMART on FHIR is interoperability. Any EHR that conforms to the SMART on FHIR standard should be able to launch our app with minimal modifications. To demonstrate interoperability, you'll try registering and launching our app in another popular sandbox made by SMART Health IT team.
Think about what settings were specific to the logica Sandbox, figure out if you need to change anything in launch-smart-sandbox.html to make it work with the SMART Health IT Launcher sandbox, and test your app out!
You'll use the SMART Health IT Sandbox to demonstrate a third app launch flow where we want to launch a standalone app that, despite being launched outside of the EHR or Patient Portal context, authenticates with the EHR and has access to the available FHIR resources.
Check out the documentation for the Standalone Launch Sequence and think through how this flow.
If you've got tons of time and motivation - or just want to write a Python web application that uses SMART on FHIR - check out the documentation for Confidential Clients and for the Python Client Library.
Think about:
- Why you would want to develop a confidential app instead of a public one.
- How would the ability to protect a
client_secret
increase authorization security. - Why a client-side web application is unable to protect a
client_secret
. - How including a
client_secret
affects the authorization sequence and subsequent access to FHIR resource.
This is a very simple client-side web app that pulls in a patient and their observations only to... do basically nothing with it except displaying it on the screen. You can use this app as a starting point for anything you come up with - so use your imagination!