Skip to content

Introduction

Overview

Warning

The SMART implementation is still in an experimental phase. There are multiple details which have to be defined. The features explained in this guide can change without a notice.

This tutorial will introduce you to launching a SMART on FHIR app from a AIQNET.

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 more interesting tools.

Note

This tutorial is based on this excellent tutorial made by the Cerner engineering team.

Prerequisites

If you’re unfamiliar with git or Github, check these out

Learning Objectives

First Steps

  1. Fork the SMART on FHIR app from Github.

  2. Clone your project to your computer.

    • Open a terminal or Git Bash.
    • Navigate to a folder where you want to keep your project.
    • Find the project url by clicking the Clone or download green 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/pmanko/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 running git checkout gh-pages. You should get confirmation that you are on the gh-pages branch.
  3. 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.

Explore the Project Folder

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 the launch_url in the SMART documentation. This page will be called by AIQNET 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 we will be redirected to it after authorization succeeds.

Register Your App

Warning

This feature is currently missing.

Launch Your App

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. These are the scenarios you’ll focus on:

  1. 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.

  2. A Patient Portal Launch: This type of launch would be initiated by a patient from a patient-facing EHR portal. A patient would be logged into their portal, and click a link or button that would launch this app in their patient context.

  3. 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.

App Launch Flow Overview

alt-text

Source: http://docs.smarthealthit.org/authorization/

alt-text

Source: https://engineering.cerner.com/smart-on-fhir-tutorial/images/ehr_launch_seq.png

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.

Authorize Your App

Now that we have our launch scenarios created and app registered, let’s talk about how SMART apps authorize with the EHR Authorization Server.

alt-text

Source: http://www.hl7.org/fhir/smart-app-launch/

  1. Your app accesses the conformance statement using the server url sent with the iss parameter and receives an url for the authorization server.

  2. 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.

  3. If authorization succeeds, the App receives an authorization code from the authorization server.

  4. The app exchanges this code for an access token by sending a request back to the server.

  5. 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!

A Quick Intro to Scopes

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:

Get Patient Data using FHIR

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.

Modify example-smart-app.js to grab desired data

  • Open the Patient Data Manager for the patient you chose for your scenarios and click on the Observation 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 inspect the output in the Chrome javascript console:
        console.log("byCodes:");
        console.log(byCodes("26478-8"));
        console.log(byCodes("2345-7"));
  • 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 the deafault_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 the index.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.

Test Your Application!

Launch App from the SMART Sandbox

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 the SMART Health IT team.

Think about what settings were specific to AIQNET, 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!

Launch App using a Stand-alone Launch

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.