Including Linked Resources
In many cases, your application may need to search for not just one resource type, but also some of the related
resources that those resources reference. For example, one might need to search for Observation resources with a
certain code, but also the Patient resources on whom the observations were made, and the Provenance for the
Observation resources as well. Using basic search requests, this would require many different API calls. The FHIR
specification contains special _include and _revinclude search parameters, which return resources linked to the
results of your search alongside in the same Bundle.
Comparison with GraphQL
In addition to these search parameters, Medplum also offers a FHIR GraphQL API that is suitable for
retrieving linked resources when you only need to traverse a few hops in the resource graph and know the exact fields on
each resource that you need. The major differences between the _(rev)include parameters and GraphQL are summarized below:
_(rev)include | GraphQL |
|---|---|
| Returns full resource JSON | Returns only specified resource fields |
| Traverses resource references via search parameters | Traverses references through special Reference.resource field |
| Can traverse up from a resource to one that references it | Can only traverse down from a resource to one it references |
_include and _revinclude
For example, the search query described above for Observation, Patient, and Provenance resources would look like this:
- TypeScript
- cURL
await medplum.searchResources('Observation', {
code: '78012-2',
_include: 'Observation:patient',
_revinclude: 'Provenance:target',
});
curl https://api.medplum.com/fhir/R4/Observation?code=78012-2&_include=Observation:patient&_revinclude=Provenance:target
Example response
[
{
resourceType: 'Observation',
id: '1',
meta: { versionId: 'b267aa05-e134-4f01-817a-5d255a691880', lastUpdated: '2022-12-21T01:55:34.799Z' },
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '260385009', display: 'Negative', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/1', display: 'Homer Simpson III' },
effectiveDateTime: '2022-11-01T19:33:00.000Z',
},
{
resourceType: 'Patient',
id: '1',
meta: {
versionId: '98a92482-bc3b-4f09-b7ce-08fea48fa135',
lastUpdated: '2023-03-22T03:05:21.361Z',
},
name: [{ given: ['Homer'], family: 'Simpson', suffix: ['III'] }],
gender: 'male',
birthDate: '1956-05-12',
},
{
resourceType: 'Provenance',
id: '1',
target: [{ reference: 'Observation/1' }],
agent: [{ who: { reference: 'Practitioner/49d111f2-ae37-47bb-b8ee-2281d024501f' } }],
},
{
resourceType: 'Observation',
id: '2',
meta: { versionId: '7777208f-426f-41b1-ab4b-0eb6d3833f09', lastUpdated: '2023-05-01T00:00:00.000Z' },
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '10828004', display: 'Positive', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/1', display: 'Homer Simpson III' },
effectiveDateTime: '2023-02-04T11:45:00.000Z',
},
{
resourceType: 'Provenance',
id: '2',
target: [{ reference: 'Observation/2' }],
agent: [{ who: { reference: 'Practitioner/49d111f2-ae37-47bb-b8ee-2281d024501f' } }],
},
{
resourceType: 'Observation',
id: '3',
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '260385009', display: 'Negative', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/2', display: 'Lisa Simpson' },
effectiveDateTime: '2022-06-12T16:03:00.000Z',
meta: { versionId: 'd4c4e4c7-a867-4b90-afd6-1c2bb84158de', lastUpdated: '2022-12-21T01:55:34.799Z' },
},
{
resourceType: 'Patient',
id: '2',
meta: {
versionId: '98a92482-bc3b-4f09-b7ce-08fea48fa135',
lastUpdated: '2023-03-22T03:05:21.361Z',
},
name: [{ given: ['Lisa'], family: 'Simpson' }],
gender: 'female',
birthDate: '2015-08-13',
},
{
resourceType: 'Provenance',
id: '3',
target: [{ reference: 'Observation/3' }],
agent: [{ who: { reference: 'Practitioner/49d111f2-ae37-47bb-b8ee-2281d024501f' } }],
},
];
The values of the _include and _revinclude parameters are not paths into the resource, but search parameters.
The _include=Observation:patient parameter adds to the search results all Patient resources referenced by the
Observation.subject field of any of the original search results. Similarly, the _revinclude parameter
adds any Provenance resources whose target field references one of the original search results. The full
graph of resources returned in the search result Bundle could look something like this:
:iterate Modifier
By default, the _include and _revinclude only include resources one hop away from resources in the search results.
In order to traverse subsequent reference links, add the :iterate modifier to the _include or _revinclude
parameter. This will cause the inclusion to apply recursively, until no more resources are found. For example,
to search for Observation resources, plus the Patient resources they refer to, plus those patients' associated
Practitioner, you might use a search API call like this:
- TypeScript
- cURL
await medplum.searchResources('Observation', {
code: '78012-2',
_include: 'Observation:patient',
'_include:iterate': 'Patient:general-practitioner',
});
curl https://api.medplum.com/fhir/R4/Observation?code=78012-2&_include=Observation:patient&_include:iterate=Patient:general-practitioner
Example response
[
{
resourceType: 'Observation',
id: '1',
meta: { versionId: 'b267aa05-e134-4f01-817a-5d255a691880', lastUpdated: '2022-12-21T01:55:34.799Z' },
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '260385009', display: 'Negative', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/1', display: 'Homer Simpson III' },
effectiveDateTime: '2022-11-01T19:33:00.000Z',
},
{
resourceType: 'Patient',
id: '1',
meta: { versionId: '98a92482-bc3b-4f09-b7ce-08fea48fa135', lastUpdated: '2023-03-22T03:05:21.361Z' },
name: [{ given: ['Homer'], family: 'Simpson', suffix: ['III'] }],
gender: 'male',
birthDate: '1956-05-12',
generalPractitioner: [{ reference: 'Practitioner/1' }],
},
{
resourceType: 'Practitioner',
id: '1',
name: [{ prefix: ['Dr.'], given: ['Julius', 'Michael'], family: 'Hibbert', suffix: ['M.D.'] }],
identifier: [{ system: 'http://hl7.org/fhir/sid/us-npi', value: '3141592654' }],
},
{
resourceType: 'Observation',
id: '2',
meta: { versionId: '7777208f-426f-41b1-ab4b-0eb6d3833f09', lastUpdated: '2023-05-01T00:00:00.000Z' },
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '10828004', display: 'Positive', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/1', display: 'Homer Simpson III' },
effectiveDateTime: '2023-02-04T11:45:00.000Z',
},
{
resourceType: 'Observation',
id: '3',
status: 'final',
code: {
coding: [{ system: 'http://loinc.org', code: '78012-2', display: 'Streptococcus pyogenes antigen, Throat' }],
},
valueCodeableConcept: {
coding: [{ code: '260385009', display: 'Negative', system: 'http://snomed.info/sct' }],
},
subject: { reference: 'Patient/2', display: 'Lisa Simpson' },
effectiveDateTime: '2022-06-12T16:03:00.000Z',
meta: { versionId: 'd4c4e4c7-a867-4b90-afd6-1c2bb84158de', lastUpdated: '2022-12-21T01:55:34.799Z' },
},
{
resourceType: 'Patient',
id: '2',
meta: {
versionId: '98a92482-bc3b-4f09-b7ce-08fea48fa135',
lastUpdated: '2023-03-22T03:05:21.361Z',
},
name: [{ given: ['Lisa'], family: 'Simpson' }],
gender: 'female',
birthDate: '2015-08-13',
generalPractitioner: [{ reference: 'Practitioner/1' }],
},
];
This query would return a Bundle containing all the resources from a linked graph like the following:
The :iterate modifier applies recursively, and can return multiple levels of results. For example,
all results in the graph shown below would be returned in the results for the following search API request:
GET /fhir/R4/Patient?_id=1&_include:iterate=Patient:link