The Language of Healthcare: Expanding FHIR Terminology Capabilities

The Language of Healthcare: Expanding FHIR Terminology Capabilities

FHIR isn’t just about moving JSON around; it’s about semantic interoperability. A “Heart Rate” observation isn’t useful unless both systems agree it’s LOINC code 8867-4. This is where the Terminology Service comes in.

In the hapi-fhir-groovy project, we’ve extended the default HAPI capabilities to provide better support for terminology-driven workflows.

What is a Terminology Service?

A Terminology Service (TS) handles operations like:

  • $expand: Get all codes in a ValueSet.
  • $lookup: Get the human-readable display name for a code.
  • $validate-code: Check if a code is valid within a specific system.
  • $translate: Convert a code from one system (e.g., ICD-10) to another (e.g., SNOMED CT).

Architectural Extension: Custom Conformance

We’ve implemented a TerminologyCapabilitiesProvider that enhances the server’s CapabilityStatement. This allows client applications to programmatically discover exactly which terminology operations and code systems our server supports.

Tutorial: Using Terminology Operations

Step 1: Expanding a ValueSet

If you need to populate a dropdown in a UI, use $expand:

GET /ValueSet/my-value-set/$expand?filter=heart

The server will return a ValueSet containing only the relevant codes.

Step 2: Validating a Code

Before saving a resource, you can verify that the clinical codes it contains are correct:

POST /ValueSet/$validate-code
Content-Type: application/fhir+json

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "system", "valueUri": "http://loinc.org" },
    { "name": "code", "valueCode": "8867-4" }
  ]
}

Tutorial: Dynamic Terminology Interception

In some cases, you might want to automatically translate codes on the fly. Using our Groovy scripting engine, you can create an interceptor that intercepts a Patient creation and adds a standardized coding:

@Interceptor
@CustomScript
class SnomedTranslator {
    @Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
    void translate(theResource) {
        // use terminology service to look up or translate codes
    }
}

The Architect’s Check: Versioning and Caching

Terminology data is often massive (SNOMED CT has 350k+ concepts). As an architect, you must plan for:

  • CodeSystem Versioning: Always specify the version when doing lookups (e.g., http://loinc.org|2.72). This ensures clinical safety during terminology upgrades.
  • Lookup Caching: Terminology operations can be expensive. Our server integrates with the Infinispan cache layer to ensure that frequent lookups (like translating a common gender code) happen in sub-millisecond time.

The Architect’s Verdict

By treating terminology as a core architectural tier, you ensure that your data is not just “storable” but “understandable”. A robust terminology service is the difference between a simple data store and a true interoperability platform that can speak the language of healthcare.


For implementation details on terminology extensions, see the src/main/java/com/gjergjsheldija/terminology package.

Related Content