Using the FHIR API to Access Data
An Application Programming Interface (API) is “a way for two or more computer programs to communicate with each other.”
FHIR defines a standard API that allows you (or your software) to request data from a FHIR-enabled server. The basics of this API should be consistent across FHIR servers, though servers can add their own custom functionality on top of the standard FHIR API.
FHIR’s API is based on an architecture called REST (REpresentational State Transfer). The details of this architecture are beyond the scope of this module, but we will cover a few high-level characteristics of REST below as they are important for understanding FHIR’s API.
It’s worth noting that most modern web-centric APIs are “RESTful” – this is helpful for software engineers without prior FHIR experience who want to work with FHIR APIs because they have likely encountered other RESTful APIs.
1 Constructing a FHIR API request
A FHIR server’s API is typically accessed via a URL1 like https://hapi.fhir.org/baseR4/
.
This URL is used to construct the API request, which typically takes the following form:
GET https://hapi.fhir.org/baseR4/Patient/591702
This would retrieve a FHIR instance of Patient for the patient with the ID 591702
.
The general structure of a FHIR API request includes the following:
GET
= HTTP “verb”, which tells the server whether you are asking for data or performing another operation (see the FHIR documentation for details)https://hapi.fhir.org/baseR4/
= URL to the FHIR APIPatient
= FHIR resource type you want591702
= The ID for the resource you want (note that an ID is not needed for some types of API requests)
You can use this information to fill out the form below to construct and run a live FHIR query below to retrieve this patient’s instance of Patient:
The response to a FHIR API request is typically in JSON format, which, like REST, is a commonly used data interchange format.
Here’s an example of what this looks like for an instance of a Patient resource:
{
"resourceType": "Patient",
"id": "1234",
"identifier":
[
{
"use": "official",
"type":
{
"coding":
[
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR",
"display": "Medical Record Number"
}
],
"text": "Medical Record Number"
},
"system": "http://hospital.smarthealthit.org",
"value": "smart-1032702"
}
],
"active": true,
"name":
[
{
"use": "official",
"family": "Shaw",
"given":
[
"Amy",
"V"
]
}
],
"telecom":
[
{
"system": "phone",
"value": "800-782-6765",
"use": "mobile"
},
{
"system": "email",
"value": "amy.shaw@example.com"
}
],
"gender": "female",
"birthDate": "2007-03-20",
"address":
[
{
"use": "home",
"line":
[
"49 Meadow St"
],
"city": "Mounds",
"state": "OK",
"postalCode": "74047",
"country": "USA"
}
]
}
Modern programming languages universally support parsing JSON, which makes it easier to work with FHIR data than if a bespoke format was used.2 JSON also is relatively easy for humans to read.
2 Common API requests for research
Researchers will typically be reading data from a FHIR server rather than modifying data on the FHIR server. Requests to read data for research purposes will typically be one of the following:
- Getting instances of resources for a specific patient
- Getting all patients that meet a certain set of criteria
Examples of API requests for these use cases are described below. For additional information on FHIR’s search capabilities, please see the Search page in the FHIR specification.
2.1 Getting instances of resources for a specific patient
The example above (GET https://hapi.fhir.org/baseR4/Patient/591702
) shows how to get the instance of Patient for the patient with the ID 591702
.
Because FHIR’s RESTful interface uses standard HTTP requests, it is possible to make GET
requests by pasting a URL like https://hapi.fhir.org/baseR4/Patient/591702
into your browser’s address bar (omit the GET
when using your browser, as loading web pages uses GET
by default).
However, it may be helpful to use an API testing tool like Postman or Hoppscotch when constructing FHIR searches for testing, or viewing longer responses. Note that caution should be used when loading real patient data with FHIR via third-party tools. The FHIR search examples in this module use synthetic data so this is not a concern here.
You can also use Python or another scripting language to make FHIR API requests and parse the responses. This Jupyter notebook demonstrates how to do this with Python.
It is possible to get resources related to this patient as well. For example, to get all the Observation resources associated with patient 591702
, make the following request:
GET https://hapi.fhir.org/baseR4/Patient?_id=591702&_revinclude=Observation:patient
Note that rather than including the ID as part of the URL like in GET https://hapi.fhir.org/baseR4/Patient/591702
, this request uses the _id
parameter. This is necessary because we need to use the search
interaction rather than the read
interaction3 to retrieve multiple instances at once.
This request also uses the _revinclude
parameter, which tells the FHIR server to follow the “reverse link” to identify instances of Observation where the reference in Observation.patient
refers to one of the instances of Patient returned by the search.
The response to a search
interaction is an instance of the Bundle resource, which contains the instances of the Patient and Observation resources returned by the server in response to the search. More information on Bundle can be found in Key FHIR Resources.
Depending on your query, the response may be too large for the sever to easily return all at once. In this case, the server may employ paging to split up the response. If it does, the response will include an entry in the link
element that indicate the URL that provides the relation="next"
page. To retrieve all the results, you will need to issue a GET
request to the next
URLs on each page of results. The last page of results will not have a next
URL populated.
Multiple types of resources
The same approach can be used to get multiple types of resources at once. The query below will include both Observation and Condition instances for the specified patient using multiple _revinclude
parameters:
GET https://hapi.fhir.org/baseR4/Patient?_id=591702&_revinclude=Observation:patient&_revinclude=Condition:patient
Get instances of a resource without including Patient
If you want to get just the instances of a resource like Observation for a patient, without including the instance of Patient, the following approach can be used:
GET https://hapi.fhir.org/baseR4/Observation?patient=591702
This instructs the server to return instances of Observation where Observation.patient=591702
.
2.2 Getting all patients that meet specified criteria
FHIR’s search
interaction does not allow for the same degree of filtering logic as a SQL-style query in a relational database. However, it does include some ability to filter with AND/OR logic, or by other criteria. Below are a few examples of this functionality.
To get all the patients who have an Observation observation with a specific value of Observation.code
, make the following request:
GET https://hapi.fhir.org/baseR4/Patient?_has:Observation:patient:code=http://loinc.org|718-7
This requests all instances of Patient that are associated with an instance of Observation via Observation.patient
, and have Observation.code=http://loinc.org|718-7
via reverse chaining. (718-7
is the LOINC for “Hemoglobin [Mass/volume] in Blood”.)
If you want the instances of Observation along with Patient, you can use this request instead:
GET https://hapi.fhir.org/baseR4/Observation?code=http://loinc.org|718-7&_include=Observation:patient
The _include
parameter tells the server to return instances of Observation where code=http://loinc.org|718-7
, and then to follow the reference in Observation.patient
and include the referenced instances as well.
It is possible to perform more complex selection and filtering operations via the FHIR search API. For example, to get the subset of these observations with hemoglobin values > 20, make this request:
GET https://hapi.fhir.org/baseR4/Observation?code=http://loinc.org|718-7&_has:Observation&value-quantity=gt20
The parameter value-quantity=gt20
tells the server to take the subset of the selected Observation instances with Observation.valueQuantity
greater than (gt
) 20. Care should be used when analyzing the response to ensure Observation.valueQuantity.units
is consistent.
A number of other logic and filtering capabilities are described in detail on in a section on the Search page in the FHIR specification.
3 Determining a FHIR server capabilities
All servers are required to support the capabilities
interaction which documents the server’s functionality. The capability interaction is of the form:
GET [base]/metadata
This request will return an instance of a resource called a CapabilityStatement that defines the behaviors supported by the server.
Instances of CapabilityStatement are often extremely long – the response from GET https://hapi.fhir.org/baseR4/metadata
is more than 25,000 lines of JSON. Therefore, if you wish to use the capabilities
interaction to discover server capabilities, you will likely need to write a script to assist with parsing the response. More information on this can be found here under “Querying the Server.” The FHIR specification has a summary table of interactions that may be available on a server, which may help in understanding the response of the capabilties
interaction.
4 Next steps
If you are interested in using the FHIR API to access data, you may want to review the following resources:
The general FHIR API documentation and the documentation specific to the
search
interaction in the FHIR specification.The modules converting from FHIR to tabular format if you are interested in extracting data from a FHIR server for analysis in software like R or Python/Pandas.
NIH/ODSS training materials on using Python/Pandas to extract data from a FHIR server and integrate it with other data sources (note that R versions of these exercises are also available):
Footnotes
URLs may only be accessible inside an institution’s firewall, or may be accessible to the public internet. Even if a FHIR server is accessible to the public internet, it may not respond to any request – depending on how it is configured, it may require authentication (like a username and password) to return any data.↩︎
FHIR servers can also typically return data in other standard formats, like XML.↩︎
GET https://hapi.fhir.org/baseR4/Patient/591702
from above is an example of theread
interaction.↩︎