Skip to content

Search Parameters

OctoFHIR supports comprehensive FHIR search capabilities including all standard modifiers, date prefixes, and advanced features like _include and _revinclude.

Search for resources using query parameters:

Terminal window
# Search for patients by family name
GET /Patient?family=Smith
# Search with multiple parameters (AND logic)
GET /Patient?family=Smith&gender=female
# Search with multiple values (OR logic)
GET /Patient?family=Smith,Johnson

String search parameters support the following modifiers:

Terminal window
# Matches "Smith", "Smithson", "Smithfield"
GET /Patient?family=Smith

Case-sensitive exact match:

Terminal window
# Matches only "Smith" (not "smith" or "SMITH")
GET /Patient?family:exact=Smith

Substring match anywhere in the value:

Terminal window
# Matches "Smith", "Blacksmith", "Smithson"
GET /Patient?family:contains=mit

Find resources where the element is present or absent:

Terminal window
# Patients without an identifier
GET /Patient?identifier:missing=true
# Patients with at least one identifier
GET /Patient?identifier:missing=false

Token search parameters (for codes, identifiers, etc.) support:

Terminal window
# Search by system and code
GET /Patient?identifier=http://hospital.org/mrn|MRN-001
# Search by code only (any system)
GET /Patient?identifier=MRN-001
# Search by system only (any code)
GET /Patient?identifier=http://hospital.org/mrn|

Search by display text rather than code:

Terminal window
# Find observations where code display contains "blood pressure"
GET /Observation?code:text=blood pressure

Exclude resources with matching codes:

Terminal window
# Patients that are NOT male
GET /Patient?gender:not=male

For Identifier searches, match by identifier type:

Terminal window
# Find patients by MRN type identifier
GET /Patient?identifier:of-type=http://terminology.hl7.org/CodeSystem/v2-0203|MR

Date search parameters support precision-aware comparisons:

PrefixMeaningExample
eqEqual (default)birthdate=eq1980-01-15
neNot equalbirthdate=ne1980-01-15
ltLess thanbirthdate=lt1990-01-01
leLess than or equalbirthdate=le1990-01-01
gtGreater thanbirthdate=gt1980-01-01
geGreater than or equalbirthdate=ge1980-01-01
saStarts afterdate=sa2024-01-01
ebEnds beforedate=eb2024-12-31
apApproximatelydate=ap2024-06-15

Combine prefixes to search within ranges:

Terminal window
# Patients born in the 1980s
GET /Patient?birthdate=ge1980-01-01&birthdate=lt1990-01-01
# Observations from January 2024
GET /Observation?date=ge2024-01-01&date=lt2024-02-01

Dates match at their precision level:

Terminal window
# Matches any date in 1980
GET /Patient?birthdate=1980
# Matches any date in January 1980
GET /Patient?birthdate=1980-01
# Matches exactly January 15, 1980
GET /Patient?birthdate=1980-01-15

Include referenced resources in the response:

Terminal window
# Search observations and include referenced Patient
GET /Observation?code=8867-4&_include=Observation:subject
# Include multiple reference types
GET /Observation?_include=Observation:subject&_include=Observation:performer

Include resources that reference the search results:

Terminal window
# Search patients and include their observations
GET /Patient?_revinclude=Observation:subject
# Include multiple reverse references
GET /Patient?_revinclude=Observation:subject&_revinclude=Condition:subject

For recursive includes (follow reference chains):

Terminal window
# Include subject and the subject's organization
GET /Observation?_include=Observation:subject&_include:iterate=Patient:organization

Return only specific elements:

Terminal window
# Return only id, name, and birthDate
GET /Patient?_elements=id,name,birthDate

Resources returned with _elements are tagged with SUBSETTED in their meta.

Return summarized resources:

ValueDescription
trueReturn summary elements only
falseReturn full resources (default)
textReturn text, id, meta, and mandatory elements
dataReturn data elements only (no text)
countReturn only the count, no entries
Terminal window
# Get summary view
GET /Patient?_summary=true
# Get just the count
GET /Patient?_summary=count

Limit the number of results:

Terminal window
# Return first 10 results
GET /Patient?_count=10

Use the link elements in the Bundle response:

{
"resourceType": "Bundle",
"type": "searchset",
"total": 100,
"link": [
{"relation": "self", "url": "..."},
{"relation": "next", "url": "...?_page=2"},
{"relation": "previous", "url": "...?_page=0"}
]
}

Sort results by one or more parameters:

Terminal window
# Sort by birthDate ascending
GET /Patient?_sort=birthdate
# Sort by birthDate descending
GET /Patient?_sort=-birthdate
# Sort by multiple fields
GET /Patient?_sort=family,-birthdate

Search using composite parameters that combine multiple values:

Terminal window
# Search by code AND value (composite parameter)
GET /Observation?code-value-quantity=http://loinc.org|8867-4$gt60

Search by properties of referenced resources:

Terminal window
# Observations for patients named "Smith"
GET /Observation?subject:Patient.family=Smith
# Observations for patients born after 1980
GET /Observation?subject:Patient.birthdate=gt1980-01-01

These parameters work on all resource types:

ParameterTypeDescription
_idtokenResource logical ID
_lastUpdateddateWhen the resource was last updated
_profileuriProfiles the resource claims to conform to
_tagtokenTags applied to the resource
_securitytokenSecurity labels on the resource
_sourceuriSource URI for the resource
Terminal window
# Active female patients named Smith, born in the 1980s,
# sorted by birthdate, returning only id and name
GET /Patient?family=Smith&gender=female&active=true&birthdate=ge1980-01-01&birthdate=lt1990-01-01&_sort=birthdate&_elements=id,name
Terminal window
# Final observations with heart rate code,
# include the patient, return first 20
GET /Observation?status=final&code=http://loinc.org|8867-4&_include=Observation:subject&_count=20
Terminal window
# Patients without phone numbers
GET /Patient?telecom:missing=true
# Observations without values
GET /Observation?value-quantity:missing=true

OctoFHIR supports creating custom SearchParameter resources that are automatically registered and immediately available for search operations.

Custom search parameters can be created in two ways:

  1. Via FHIR Packages - Include SearchParameter resources in your Implementation Guide
  2. Via REST API - Create SearchParameter resources directly through the FHIR API

Create a SearchParameter resource using the standard FHIR create operation:

Terminal window
POST /fhir/SearchParameter
Content-Type: application/fhir+json
{
"resourceType": "SearchParameter",
"url": "http://example.org/SearchParameter/patient-custom-field",
"name": "PatientCustomField",
"code": "custom-field",
"status": "active",
"description": "Search by custom patient field",
"base": ["Patient"],
"type": "string",
"expression": "Patient.extension.where(url='http://example.org/custom-field').valueString"
}

Response:

{
"resourceType": "SearchParameter",
"id": "12345",
"meta": {
"versionId": "1",
"lastUpdated": "2025-01-02T10:30:00Z"
},
"url": "http://example.org/SearchParameter/patient-custom-field",
"code": "custom-field",
...
}

When you create, update, or delete a SearchParameter resource:

  1. FHIRPath Validation - The expression is validated for syntax correctness
  2. Immediate Registration - The parameter is registered in the search registry
  3. Zero Downtime - Available immediately without server restart
  4. Lock-Free - No impact on concurrent search operations
Terminal window
# Create the SearchParameter
POST /fhir/SearchParameter { ... }
# Immediately use it in search (no restart needed!)
GET /fhir/Patient?custom-field=some-value

Invalid FHIRPath expressions are rejected:

Terminal window
POST /fhir/SearchParameter
{
"resourceType": "SearchParameter",
"expression": "Patient..invalid..syntax", # Invalid!
...
}

Response (400 Bad Request):

{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "invalid",
"diagnostics": "Invalid FHIRPath expression: unexpected token"
}]
}

Required fields:

  • code - The search parameter name (used in queries)
  • url - Canonical URL (must be unique)
  • type - Parameter type: string, token, reference, date, number, quantity, uri, composite, special
  • base - Resource types this parameter applies to (array)

Optional but recommended:

  • expression - FHIRPath expression defining what to search
  • description - Human-readable description
  • modifier - Supported modifiers (:exact, :contains, etc.)
  • comparator - Supported comparators for numbers/dates (eq, gt, lt, etc.)
  • target - Target resource types (for reference type parameters)

Search by extension values:

{
"resourceType": "SearchParameter",
"url": "http://example.org/SearchParameter/patient-ethnicity",
"code": "ethnicity",
"type": "token",
"base": ["Patient"],
"expression": "Patient.extension.where(url='http://example.org/ethnicity').valueCoding"
}

Usage:

Terminal window
GET /fhir/Patient?ethnicity=http://example.org/ethnicity-codes|hispanic

Search by nested fields:

{
"resourceType": "SearchParameter",
"url": "http://example.org/SearchParameter/patient-home-city",
"code": "home-city",
"type": "string",
"base": ["Patient"],
"expression": "Patient.address.where(use='home').city"
}

Usage:

Terminal window
GET /fhir/Patient?home-city=Boston

Apply the same parameter to multiple resource types:

{
"resourceType": "SearchParameter",
"url": "http://example.org/SearchParameter/clinical-custom-status",
"code": "custom-status",
"type": "token",
"base": ["Observation", "Condition", "Procedure"],
"expression": "%resource.extension.where(url='http://example.org/custom-status').valueCode"
}

Usage:

Terminal window
GET /fhir/Observation?custom-status=reviewed
GET /fhir/Condition?custom-status=reviewed
GET /fhir/Procedure?custom-status=reviewed

Search by custom references:

{
"resourceType": "SearchParameter",
"url": "http://example.org/SearchParameter/observation-custom-performer",
"code": "custom-performer",
"type": "reference",
"base": ["Observation"],
"target": ["Practitioner", "Organization"],
"expression": "Observation.extension.where(url='http://example.org/custom-performer').valueReference"
}

Usage:

Terminal window
GET /fhir/Observation?custom-performer=Practitioner/12345

Update a SearchParameter to modify its behavior:

Terminal window
PUT /fhir/SearchParameter/12345
{
"resourceType": "SearchParameter",
"id": "12345",
"url": "http://example.org/SearchParameter/patient-custom-field",
"code": "custom-field",
"type": "string",
"base": ["Patient"],
"expression": "Patient.extension.where(url='http://example.org/updated-field').valueString",
"modifier": ["exact", "contains"] # Added modifiers
}

The updated parameter is immediately available with new behavior.

Delete a SearchParameter when no longer needed:

Terminal window
DELETE /fhir/SearchParameter/12345

After deletion:

  • The parameter is removed from the search registry
  • Queries using this parameter will fail with “unknown search parameter” error
  • Existing data is unchanged (only the search capability is removed)

OctoFHIR’s search parameter architecture is designed for high-performance production workloads:

Lock-Free Reads:

  • Search queries never block on registry access
  • Single atomic load (~1-5 nanoseconds)
  • Zero contention during concurrent searches

Incremental Updates:

  • SearchParameter CRUD operations update registry incrementally
  • No full registry reload needed
  • Update time: ~100-500 nanoseconds

Query Cache:

  • Automatically cleared when parameters change
  • Prevents stale query results
  • Minimal performance impact
  1. Use Canonical URLs - Follow URI naming conventions (e.g., http://your-org.org/SearchParameter/name)
  2. Test FHIRPath Expressions - Validate expressions work correctly before deployment
  3. Document Custom Parameters - Add clear descriptions and examples
  4. Version Your Parameters - Include version in URL when making breaking changes
  5. Use Packages for Production - Package-based parameters ensure consistency across instances
  • No Semantic Validation - FHIRPath expressions are checked for syntax, not semantics
  • No Runtime Type Checking - Expression type mismatches fail gracefully at query time
  • Extension-Only - Custom parameters typically target extensions (core FHIR fields already have parameters)

Parameter not found:

Terminal window
GET /fhir/Patient?my-param=value
# Error: Unknown search parameter 'my-param'
  • Verify SearchParameter was created successfully
  • Check the code field matches the query parameter name
  • Ensure base includes the resource type you’re querying

No results with valid parameter:

Terminal window
GET /fhir/Patient?custom-field=value
# Returns empty Bundle
  • Verify the FHIRPath expression matches your data structure
  • Check extension URLs match exactly (case-sensitive)
  • Test the expression against sample resources

Invalid expression error:

Terminal window
POST /fhir/SearchParameter
# Error: Invalid FHIRPath expression
  • Review FHIRPath syntax
  • Use parentheses for complex expressions
  • Test expression with FHIRPath evaluator tools