Skip to main content

Basic Queries

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.

Access Policies

When using GraphQL, access policies are enforced, so users will not be able to read or edit any resources (or inner fields) they do not have access to.

How to perform FHIR 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.

Search Modifiers

The official FHIR GraphQL specification currently does not support search modifiers such as :not, :missing, and :contains. If you'd like to participate or learn more, join the discussion here.

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.

Chained Search in GraphQL

When searching on references in GraphQL, you cannot filter on the parameters of the referenced resources. This is called chained search and it is not supported by the FHIR GraphQL spec. However, it is supported in the FHIR Rest API. For more details see the Chained Search docs.

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',
},
],
},
],
},

If more powerful filtering capabilities are required, a FHIRPath expression can be evaluated to select which list items are included in the response. The expression should evaluate to true for an item to be included. This example selects all patient names without a family part:

{
PatientList {
resourceType
id
name(fhirpath: "family.exists().not()") {
use given family text
}
}
}
Example Response
  data: {
PatientList: [
{
resourceType: 'Patient',
id: 'patient-id-1',
name: [
{
use: 'usual',
given: ['Johnny'],
family: null,
text: null,
},
{
use: 'anonymous',
given: null,
family: null,
text: 'd87a7e2f264680fe',
},
],
},
],
},
Query Performance

Evaluating FHIRPath expressions can be relatively expensive; consider whether results could easily be filtered by the client instead.

See the "List Navigation" 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.