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.
Schema introspection is supported on Mepdlum, but for security and performance reasons, it is disabled by default. To enable it, you will need to enable the introspectionEnabled
flag in your server config.
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
.
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.
When using FHIR GraphQL, you must still use FHIR search parameters; however, 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.
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
:
- 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.
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:
- 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',
},
],
},
],
},
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:
- GraphQL
- TypeScript
{
PatientList {
resourceType
id
name(fhirpath: "family.exists().not()") {
use given family text
}
}
}
await medplum.graphql(`{
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',
},
],
},
],
},
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
.
- 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.