Learning Objectives

The objective for this exercise is to introduce you to the basic mechanisms for working with FHIR.

For this exercise, we will walk you through the following steps:

We will use the fhircrackr library to handle querying from a FHIR server and converting the response into an R dataframe.

Let’s get our environment set up:

library(fhircrackr)

Step 1: Query the FHIR Server

First let’s connect to our FHIR server for data retrieval.

Generally speaking the pattern for a RESTful GET query appended to a URL will take the form of:

VERB [url]/[Resource] {?parameter=[value]}

See http://hl7.org/fhir/R4/http.html for more details.

Let’s attempt to do a sample load from our example FHIR server by requesting Patient resources for the available patients.

In this case, we want to modify the general pattern with:

fhir_server <- "https://api.logicahealth.org/researchonfhir/open/"
request <- fhir_url(url = fhir_server, resource = "Patient")
patient_bundle <- fhir_search(request = request, max_bundles = 1, verbose = 1)
## Starting download of 1 bundles of resource type https://api.logicahealth.org/researchonfhir/open/Patient from FHIR base URL https://api.logicahealth.org/researchonfhir/open/Patient.
## 
## Download completed. Number of downloaded bundles was limited to 1 bundles, this is less than the total number of bundles available.
patient_bundle
## An object of class "fhir_bundle_list"
## [[1]]
## A fhir_bundle_xml object
## No. of entries : 50
## Self Link: https://api.logicahealth.org/researchonfhir/open/Patient
## Next Link: https://api.logicahealth.org/researchonfhir/open?_getpages=ac415e48-23bf-4700-9f57-36069b6aef9d&_getpagesoffset=50&_count=50&_pretty=true&_bundletype=searchset 
## 
## {xml_node}
## <Bundle>
##  [1] <id value="ac415e48-23bf-4700-9f57-36069b6aef9d"/>
##  [2] <meta>\n  <lastUpdated value="2022-03-10T11:42:45.470+00:00"/>\n</meta>
##  [3] <type value="searchset"/>
##  [4] <total value="70"/>
##  [5] <link>\n  <relation value="self"/>\n  <url value="https://api.logicaheal ...
##  [6] <link>\n  <relation value="next"/>\n  <url value="https://api.logicaheal ...
##  [7] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
##  [8] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
##  [9] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [10] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [11] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [12] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [13] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [14] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [15] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [16] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [17] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [18] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [19] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## [20] <entry>\n  <fullUrl value="https://api.logicahealth.org/researchonfhir/o ...
## ...

If the above request works, you should see a preview of the first few lines of XML representing the FHIR resources from patient_bundle above.

Step 2: Convert response from server into a data frame

The fhircrackr library uses the fhir_table_description() function to translate the hierarchical XML resource returned by the FHIR server into a tabular format (i.e., a data frame) that works with typical analysis approaches in R.

This function creates a definition mapping parts of the XML representation of the resource onto columns in the data frame that will be generated. The XML elements are identified using XPath, a query language for XML.

table_desc_patient <- fhir_table_description(
    resource = "Patient",

    cols = c(
            id           = "id",
            given_name    = "name/given",
            family_name   = "name/family",
            gender        = "gender",
            birthday      = "birthDate",
            birthTime     = "extension[@url=\"http://hl7.org/fhir/StructureDefinition/patient-birthTime\"]/valueDateTime"
        )

)

Many of the XPath queries you will use wil be straight-forward, like id and name/given. In some cases, you may need to construct more complex queries like the one to extract birthTime from the patient-birthTime extension in the FHIR resource instance. You can use a tool like this XPath tester to help generate XPaths. For more information on XPath, see this guide.

Once the table description is created, we can create a data frame:

df_patient <- fhir_crack(bundles = patient_bundle, design = table_desc_patient, verbose = 0)
## Warning in fhir_crack(bundles = patient_bundle, design = table_desc_patient, : In the cols element of the design, you specified XPath expressions containing '//' which point to an arbitrary level in the resource. 
## This can result in unexpected behaviour, e.g. when the searched element appears on different levels of the resource. 
## We strongly advise to only use the fully specified relative XPath in the cols element, e.g. 'ingredient/strength/numerator/code' instead of search paths like '//code'. 
## This warning is thrown for the following data.frame descriptions: birthTime
df_patient

You should see the name, gender, birthday and birth time for 50 patients.