Skip to main content

GraphQL for FHIR

Overview

This guide will walk you through how to use the FHIR GraphQL API with Medplum. Clinical data is often comprised of multiple FHIR resources, and the FHIR GraphQL API makes it easy to query multiple linked resources in a single request.

The GraphQL API also allows you to request specific elements, rather than full resources, which can be more efficient in bandwidth constrained settings.

To experiment with the API, you can use Medplum's interactive GraphQL environment at graphiql.medplum.com. You can log in with your Medplum credentials, and run these example queries in the GraphiQL IDE.

How to perform basic GraphQL queries

GraphQL queries allow you to request specific resourced fields. In a FHIR GraphQL query, you will use the resource type as the root, followed by the ID in parentheses. The requested fields are enclosed in curly braces.

For example, to request a Patient by ID:

{
Patient(id: "example-id") {
resourceType
id
name {
text
}
address {
text
}
}
}
Example Response
  {
data: {
Patient: {
resourceType: 'Patient',
id: 'example-id',
name: [
{
text: 'John Doe',
},
],
address: [
{
text: '123 Main St, Springfield',
},
],
},
},
};

This query retrieves the resourceType, id, name, and address of the specified Patient.

How to FHIR perform searches with GraphQL

To perform a FHIR search, append the word "List" to the FHIR resource type. For example, to search for Patient resources use "PatientList". You will specify search parameters as query parameters, similarly to basic REST search.

GraphQL also allows you to alias returned fields to make the results more readable.

Warning

In FHIR GraphQL, the search parameter names use snake_case instead of the kebab-case commonly used in the FHIR REST API.

To search for a list of Patient resources with a specific name and city:

{
PatientList(name: "Eve", address_city: "Philadelphia") {
resourceType
id
name {
family
given
}
address {
line
city
state
postalCode
}
}
}
Example Response
  data: {
patients: [
{
resourceType: 'Patient',
id: 'example-id-1',
name: [
{
family: 'Johnson',
given: ['Eve'],
},
],
address: [
{
line: ['456 Market St'],
city: 'Philadelphia',
state: 'PA',
postalCode: '19104',
},
],
},
{
resourceType: 'Patient',
id: 'example-id-2',
name: [
{
family: 'Smith',
given: ['Eve'],
},
],
address: [
{
line: ['789 Broad St'],
city: 'Philadelphia',
state: 'PA',
postalCode: '19107',
},
],
},
],
},

This query searches for Patient resources with the name "Eve" and a city of "Philadelphia", and aliases the list of patients as patients in the response.

See the "Searching Resources" section of the FHIR GraphQL specification for more information.

Resolving nested resources with the resource element

Clinical data is often spread across multiple FHIR resources that reference each other. The FHIR GraphQL API contains a special resource element to resolve these references and retrieve the nested resources.

To resolve a reference, you need to use the GraphQL inline fragment syntax (... on ResourceType). Inline fragments allow you to request fields on a specific type within a more general parent type. This is important for FHIR GraphQL queries because the resource field can return different types of resources depending on the reference.

For example, to retrieve a DiagnosticReport and all the Observation resources referenced by DiagnosticReport.result:

{
DiagnosticReport(id: "example-id-1") {
resourceType
id
result {
resource {
... on Observation {
resourceType
id
valueQuantity {
value
unit
}
}
}
}
}
}
Example Response
  data: {
DiagnosticReport: {
resourceType: 'DiagnosticReport',
id: 'example-id-1',
result: [
{
resource: {
resourceType: 'Observation',
id: 'observation-id-1',
valueQuantity: {
value: 5.5,
unit: 'mg/dL',
},
},
},
{
resource: {
resourceType: 'Observation',
id: 'observation-id-2',
valueQuantity: {
value: 3.2,
unit: 'mg/dL',
},
},
},
],
},
},

This query retrieves a DiagnosticReport and the Observation resources associated with it.

See the "Resource References" section of the FHIR GraphQL specification for more information.

Searching reverse references using the _reference keyword

FHIR GraphQL also supports reverse-reference searches, which allow you to find resources that point to the current resource.

In a reverse-include search, you use a nested <ResourceType>List block to search for the resources that reference the current resource. The special _reference search parameter indicates which search parameter from the target resource references the current resource.

In the example below, we first search for a Patient by id, and then find all the Encounter resources whose Encounter.patient search parameter points to the current Patient.

{
Patient(id: "example-patient-id") {
resourceType
id
encounters: EncounterList(_reference: patient) {
resourceType
id
}
}
}
Example Response
  data: {
Patient: {
resourceType: 'Patient',
id: 'example-patient-id',
encounters: [
{
resourceType: 'Encounter',
id: 'encounter-id-1',
},
{
resourceType: 'Encounter',
id: 'encounter-id-2',
},
],
},
},

See the "Reverse References" section of the FHIR GraphQL specification for more information.

Filtering lists with field arguments

FHIR GraphQL supports filtering array properties using field arguments. For example, you can filter the Patient.name array by the use field:

{
PatientList {
resourceType
id
name(use: "official") {
given
family
}
}
}
Example Response
  data: {
PatientList: [
{
resourceType: 'Patient',
id: 'patient-id-1',
name: [
{
given: ['John'],
family: 'Doe',
},
],
},
],
},

Another common use is to filter an extension array by url:

{
PatientList {
resourceType
id
extension(url: "https://example.com/123") {
valueString
}
}
}
Example Response
  data: {
PatientList: [
{
resourceType: 'Patient',
id: 'patient-id-1',
extension: [
{
valueString: 'Sample extension value',
},
],
},
],
},

See the "List Navigation" section of the FHIR GraphQL specification for more information.

Connection API

Using the normal "List" search (i.e., "PatientList") is the most common way to search for resources. However, the FHIR GraphQL specification also supports the Connection API, which is a more complex way to search for resources.

The most immediate advantage to the Connection API is better support for pagination and retrieving total counts. The Conenction API also includes more features from FHIR Bundle such as mode and score.

To use the Connection API, append "Connection" to the resource type rather than "List". For example, use "PatientConnection" instead of "PatientList".

Here is an example of searching for a list of Patient resources using the Connection API:

{
PatientConnection {
count
edges {
resource {
resourceType
id
name { given family }
}
}
}
}
Example Response
  data: {
PatientConnection: {
count: 2,
edges: [
{
resource: {
resourceType: 'Patient',
id: 'example-patient-id-1',
name: [
{
given: ['Bart'],
family: 'Simpson',
},
],
},
},
{
resource: {
resourceType: 'Patient',
id: 'example-patient-id-2',
name: [
{
given: ['Homer'],
family: 'Simpson',
},
],
},
},
],
},
},

See the "Connection API" section of the FHIR GraphQL specification for more information.

Putting it all together

The FHIR GraphQL syntax is a powerful way to query for multiple related resources in a single HTTP call. The following example combines previous concepts.

This query searches for a list of Patients named "Eve", living in "Philadelphia", and then searches for all DiagnosticReports linked to each Patient along with their corresponding Observations.

{
# Search for a list of Patients named "Eve", living in "Philadelphia"
PatientList(name: "Eve", address_city: "Philadelphia") {
resourceType
id
name {
family
given
}
address {
line
city
state
postalCode
}
# Search for DiagnosticReports linked to each Patient
reports: DiagnosticReportList(_reference: subject) {
resourceType
id
# Resolve the Observations referenced by DiagnosticReport.result
result {
resource {
... on Observation {
resourceType
id
valueQuantity {
value
unit
}
}
}
}
}
}
}
Example Response
  data: {
PatientList: [
{
resourceType: 'Patient',
id: 'patient-id-1',
name: [
{
family: 'Smith',
given: ['Eve'],
},
],
address: [
{
line: ['123 Main St'],
city: 'Philadelphia',
state: 'PA',
postalCode: '19107',
},
],
reports: [
{
resourceType: 'DiagnosticReport',
id: 'report-id-1',
result: [
{
resource: {
resourceType: 'Observation',
id: 'observation-id-1',
valueQuantity: {
value: 5.5,
unit: 'mg/dL',
},
},
},
],
},
],
},
{
resourceType: 'Patient',
id: 'patient-id-2',
name: [
{
family: 'Johnson',
given: ['Eve'],
},
],
address: [
{
line: ['456 Oak St'],
city: 'Philadelphia',
state: 'PA',
postalCode: '19107',
},
],
reports: [
{
resourceType: 'DiagnosticReport',
id: 'report-id-2',
result: [
{
resource: {
resourceType: 'Observation',
id: 'observation-id-2',
valueQuantity: {
value: 6.7,
unit: 'mg/dL',
},
},
},
],
},
],
},
],
},

Conclusion

With a deeper understanding of the FHIR GraphQL syntax, you can now leverage build efficient and flexible FHIR queries for your applications. Remember to experiment with the API at graphiql.medplum.com as you develop your application.