FHIR Search
When working with the Oystehr FHIR API you will regularly need to search for resources matching a search query. Search allows you to join, filter, sort, and so much more (opens in a new tab).
To get you started with FHIR search, we'll go over the most common search parameters and how to use them.
Search Basics
To perform a search query, you need a resource type and a search parameter. For example, to search for all patients with the name "Jon", you would would look up the appropriate search parameter in the Patient resource documentation (opens in a new tab). In this case, the search parameter is given
.
You can then use the search parameter in a search query with either the API or SDK:
Search for all patients named "Jon" with the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'given',
value: 'Jon',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();
Successful search queries will return a Bundle (opens in a new tab) resource containing the matching resources. The Bundle resource is used to convey an array of FHIR resources. As an example, the above query might return the following response:
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"fullUrl": "https://fhir-api.zapehr.com/Patient/6bbdbadf-4f60-4bdd-8c54-b37970c584b2",
"resource": {
"resourceType": "Patient",
"active": true,
"name": [
{
"given": ["Jon"],
"family": "Snow"
}
],
"id": "6bbdbadf-4f60-4bdd-8c54-b37970c584b2",
"meta": {
"versionId": "ef4e3e20-4103-4df5-8f89-b4f49d6310b3",
"lastUpdated": "2023-11-15T18:11:31.740Z"
}
},
"search": {
"mode": "match"
}
}
],
"link": [
{
"relation": "self",
"url": "https://testing.fhir-api.zapehr.com/Patient?_count=20&_elements=&given=Jon"
},
{
"relation": "first",
"url": "https://testing.fhir-api.zapehr.com/Patient?_count=20&_elements=&_offset=0&given=Jon"
}
]
}
Any resources matching the search criteria will be included in the entry
array. In this case, there is only one patient named "Jon" in the system, so only one resource is returned.
The link
array contains relations like first
, prev
, next
, and last
which you can use to fetch other pages when there was more matching data than was returned in the query. In this case we only have one page of results, so only self
and first
are returned.
You can search for resources using a GET
request, as in the examples above, or using a POST
request. For POST
requests, the URL must contain /:resource/_search
, as opposed to /:resource
, which is used for GET
requests. The following example highlights this difference:
Example
Search for all patients named "Jon" with a GET request:
curl --location 'https://fhir-api.zapehr.com/r4/Patient?given=Jon' \
--header 'Authorization: Bearer <your_access_token>' \
--header 'x-zapehr-project-id: <your_project_id>'
Searches With Long Parameters
The Oystehr FHIR API has a limit of 10KB for the length of a URL. Should you exceed this limit, your request will fail with HTTP Status Code 414
. If you need to perform a search with a long parameter, or with many parameters, you can use a POST
request to avoid the URL length limit. See the example above for cURL syntax.
The Oystehr TypeScript SDK uses POST
requests for all search queries, so you don't need to worry about URL length limits when using the SDK.
Total Count
When performing a FHIR search, the resulting Bundle
includes a total
attribute. This represents the total number of matches for the search, regardless of page size. By default this total is an estimate. You may want an exact count to facilitate exhaustive listing, or not to bother with a count at all. You can control this behavior by including the _total
parameter in your search parameters:
none
— Do not include atotal
attribute on the responseBundle
estimate
— Include an estimatedtotal
on the responseBundle
; this is the default behavioraccurate
— Include an exacttotal
for the search; searches using this parameter will see a performance penalty
For more information about this search parameter, see the FHIR Search documentation (opens in a new tab).
Search Modifiers
Search modifiers are used to modify the behavior of a search parameter. For example, you can use the not
modifier to search for a resource that does not have a certain value for a field. Modifiers are appended to the end of a search parameter with a colon. For example, to search for all patients that are not active, you would use the not
modifier on the active
search parameter:
Search for all patients that are not active using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'active:not',
value: 'true',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();
Here are some of the most frequently used modifiers:
:not
— Search for resources that do not have a certain value for a "token" property. Token (opens in a new tab) search parameters are used when searching for an exact match for a code or identifier.:exact
— Search for resources that have an exact match for a "string" property.:contains
— Search for resources that contain a certain value for a "string" or "uri" property.:missing
— Search for resources that do not have a certain property.
The full list of modifiers can be found in the FHIR Search documentation (opens in a new tab).
Sorting
You can sort the results of a search query by using the _sort
parameter. For example, to sort patients alphabetically by their given name, you would use the given
search parameter with the _sort
parameter:
Search for all patients sorted by given name using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: '_sort',
value: 'given',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();
Sort the opposite direction by adding a -
before the parameter name like, _sort=-given
.
You can sort by multiple parameters by separating them with a comma, _sort=given,family
.
Limiting Page Size
Individual FHIR resources can be quite large, so to keep searches running quickly, you may want to limit the number of resources returned in one page. You can do this with the _count
parameter:
Search for all patients returning only ten in each page using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: '_count',
value: '10',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();
You can get the next page of results by using the link
relation next
, as described in the Search Basics section.
Joining Referenced Resources
The _include
and _revinclude
parameters enable returning referenced resources in search results. You can think of this like a JOIN
in SQL.
For example, if you were building an appointments feature in an EHR, you might want to query up appointments to show a calendar of upcoming appointments. For every appointment you query with your search, you also want the information about the patient the appointment is for. You can do this with the _include
parameter:
Search for appointments joining in their referenced patients with the v3 SDK:
import { Appointment } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<Appointment | Patient>*/ = await oystehr.fhir.search<Appointment | Patient>({
resourceType: 'Appointment',
params: [
{
name: '_include',
value: 'Appointment:patient',
},
],
});
The above query will return a Bundle containing all appointments, and for each appointment, the patient resource will be included in the entry
array. The patient resource will be included in the entry
array, and its search.mode
will be include
:
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"fullUrl": "https://fhir-api.zapehr.com/Appointment/2abde332-dd3e-4e3f-a317-4652cf32d991",
"resource": {
"resourceType": "Appointment",
"status": "booked",
"start": "2023-12-10T09:00:00Z",
"end": "2023-12-10T10:00:00Z",
"participant": [
{
"actor": {
"reference": "Patient/542754df-9215-4b54-ac6e-870eaffed1af"
},
"required": "required",
"status": "accepted"
}
],
"id": "2abde332-dd3e-4e3f-a317-4652cf32d991",
"meta": {
"versionId": "1ca1ef9a-acd1-499a-8ebe-ed60e5b7ca4f",
"lastUpdated": "2023-11-16T04:02:06.227Z"
}
},
"search": {
"mode": "match"
}
},
{
"fullUrl": "https://fhir-api.zapehr.com/Patient/542754df-9215-4b54-ac6e-870eaffed1af",
"resource": {
"resourceType": "Patient",
"active": true,
"name": [
{
"given": [
"Jon"
],
"family": "Snow"
}
],
"address": [
{
"use": "home",
"type": "physical",
"text": "Winterfell"
}
],
"id": "542754df-9215-4b54-ac6e-870eaffed1af",
"meta": {
"versionId": "c2047012-a48c-44e8-a77b-cdb3c2ba7fea",
"lastUpdated": "2023-11-16T03:24:31.230Z"
}
},
"search": {
"mode": "include"
}
}
],
...
}
_revinclude
is just like _include
, except it returns resources that reference the resource you are searching for. If, when searching for Patients, you wanted to also return Appointments that reference those patients, you could use _revinclude
. You could get basically the same result as above by searching for patients and "_revincluding" their appointments:
Search for patients joining in appointments which reference them with the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<Appointment | Patient>*/ = await oystehr.fhir.search<Appointment | Patient>({
resourceType: 'Patient',
params: [
{
name: '_revinclude',
value: 'Appointment:patient',
},
],
});
name
Search Parameter
The name
search parameter is used to match any of the string fields in a HumanName
resource, including family, given, prefix, suffix, and/or text. A check on each field is performed separately, and a resource that has any matching field is added to the response.
Examples
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your access token>",
});
// corresponds to the SQL expression: LIKE "Anna Maria Juanita%"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name',
value: 'Anna Maria Juanita',
},
],
})).unbundle();
// corresponds to the SQL expression: = "Anna Maria Juanita"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:exact',
value: 'Anna Maria Juanita',
},
],
})).unbundle();
// corresponds to the SQL expression: LIKE "%Anna Maria Juanita%"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:contains',
value: 'Anna Maria Juanita',
},
],
})).unbundle();
Additional Features
You can perform a search on several alternatives for the parameter value by using a comma separator (which is equal to combining results by OR).
Examples
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your access token>",
});
// will return all resources that match Anna, Mari, or Juanita
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:exact',
value: 'Anna,Maria,Juanita',
},
],
})).unbundle();
Additional Resources
- Learn more about FHIR search in the FHIR Search documentation (opens in a new tab).
- Connect with us in the Oystehr Slack Workspace (opens in a new tab) for help crafting a tricky search query.