Using the FHIR API to Access Data

Learning objectives
  1. Understand the basics of how to access data via the FHIR API.
  2. Describe common types of searches to read data from a FHIR server for research.
Relevant roles:
  • Informaticist
  • Software Engineer

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.

Try a FHIR API request

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 API
  • Patient = FHIR resource type you want
  • 591702 = 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:

  1. Getting instances of resources for a specific patient
  2. 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.

Making requests to a FHIR server

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/591702into 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:

Footnotes

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

  2. FHIR servers can also typically return data in other standard formats, like XML.↩︎

  3. GET https://hapi.fhir.org/baseR4/Patient/591702 from above is an example of the read interaction.↩︎