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:
- GraphQL
- Typescript
- cURL
{
Patient(id: "example-id") {
resourceType
id
name {
text
}
address {
text
}
}
}
const patientId = 'example-id';
await medplum.graphql(`
{
Patient(id: "${patientId}") {
resourceType
id
name {
text
}
address {
text
}
}
}`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $your_access_token" \
-d '{"query": "{ 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.
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:
- GraphQL
- Typescript
- cURL
{
PatientList(name: "Eve", address_city: "Philadelphia") {
resourceType
id
name {
family
given
}
address {
line
city
state
postalCode
}
}
}
await medplum.graphql(`
{
patients: PatientList(name: "Eve", address_city: "Philadelphia") {
resourceType
id
name {
family
given
}
address {
line
city
state
postalCode
}
}
}`);
curl 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ 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
:
- GraphQL
- Typescript
- cURL
{
DiagnosticReport(id: "example-id-1") {
resourceType
id
result {
resource {
... on Observation {
resourceType
id
valueQuantity {
value
unit
}
}
}
}
}
}
await medplum.graphql(`
{
DiagnosticReport(id: "example-id-1") {
resourceType
id
result {
resource {
... on Observation {
resourceType
id
valueQuantity {
value
unit
}
}
}
}
}
}`);
curl 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ 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.
- GraphQL
- Typescript
- cURL
{
Patient(id: "example-patient-id") {
resourceType
id
encounters: EncounterList(_reference: patient) {
resourceType
id
}
}
}
await medplum.graphql(`
{
Patient(id: "example-patient-id") {
resourceType
id
encounters: EncounterList(_reference: patient) {
resourceType
id
}
}
}`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ 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:
- GraphQL
- Typescript
- cURL
{
PatientList {
resourceType
id
name(use: "official") {
given
family
}
}
}
await medplum.graphql(`
{
PatientList {
resourceType
id
name(use: "official") {
given
family
}
}
}
`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ PatientList(family: \"doe\") { resourceType id name(use: \"official\") { use given family } extension(url: \"https://example.com/extension-url-2\") { value : valueString } } }"}'
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
:
- GraphQL
- Typescript
- cURL
{
PatientList {
resourceType
id
extension(url: "https://example.com/123") {
valueString
}
}
}
await medplum.graphql(`
{
PatientList {
resourceType
id
extension(url: "https://example.com/123") {
valueString
}
}
}
`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ 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:
- GraphQL
- Typescript
- cURL
{
PatientConnection {
count
edges {
resource {
resourceType
id
name { given family }
}
}
}
}
await medplum.graphql(`
{
PatientConnection {
count
edges {
resource {
resourceType
id
name { given family }
}
}
}
}
`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
-d '{"query":"{ 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
.
- GraphQL
- Typescript
- cURL
{
# 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
}
}
}
}
}
}
}
await medplum.graphql(`
{
PatientList(name: "Eve", address_city: "Philadelphia") {
resourceType
id
name {
family
given
}
address {
line
city
state
postalCode
}
reports: DiagnosticReportList(_reference: subject) {
resourceType
id
result {
resource {
... on Observation {
resourceType
id
valueQuantity {
value
unit
}
}
}
}
}
}
}
`);
curl -X POST 'https://api.medplum.com/fhir/R4/$graphql' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $your_access_token" \
--data-raw '{"query":"query { PatientList(name: \"Eve\", address_city: \"Philadelphia\") { resourceType id name { family given } address { line city state postalCode } DiagnosticReportList(_reference: subject) { resourceType id 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.