Spring Data Commons implementation for HAPI FHIR (Part 2)

Kostiantyn Ivanov
3 min readSep 2, 2023

--

Previous part:
Spring Data Commons implementation for HAPI FHIR (Part 1)

What is FHIR?

FHIR (Fast Healthcare Interoperability Resources), is a popular standard for electronic health data exchange and interoperability in the healthcare industry.

Key features of FHIR include:

Resource-based: FHIR represents healthcare information as discrete resources, making it easy to identify, access, and manipulate specific pieces of data.

RESTful API: FHIR uses a RESTful (Representational State Transfer) API design, which is a widely adopted approach for web-based data exchange. This makes it accessible via HTTP and can be used with common web technologies.

How to use it?

  • You can provide your own FHIR server using any of opensource solutions (https://cloud.google.com/healthcare-api/docs/how-tos/fhir)
  • You can use vendor-based implementation (standalone or cloud)
  • You can use cloud based solution from popular cloud platforms (such a GCP)
  • You can be just a client of an existing FHIR server (which can be provided to you by other company

What is HAPI FHIR?

HAPI FHIR s a complete implementation of the HL7 FHIR standard for healthcare interoperability in Java. It wraps serialization, http calls to FHIR Repository, deserialization and provides us prepared POJOs with clinical data.

Here is example of usage:

    public List<Patient> findAllByName(String name) {
// Create a context and a client
FhirContext ctx = FhirContext.forR4();
String serverBase = "http://hapi.fhr.org/baseR4";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);

// We'll populate this list
List<Patient> patients = new ArrayList<>();

// We'll do a search for all Patients and extract the first page
Bundle bundle = client.search()
.forResource(Patient.class)
.where(Patient.NAME.matches().value("smith"))
.returnBundle(Bundle.class)
.execute();
patients.addAll(BundleUtil.toListOfResources(ctx, bundle));

// Load the subsequent pages
while (bundle.getLink(IBaseBundle.LINK_NEXT) != null) {
bundle = client.loadPage().next(bundle).execute();
patients.addAll(BundleUtil.toListOfResources(ctx, bundle));
}

return patients;
}

Everything looks great but the issue is — this code it pretty wordy. And the things are going to be even worse if we have a bunch of filters:

    public List<Patient> findAllPatientsByFilters(String name, String organizationId, 
String practitionerId, int limit...) {

// Create a context and a client
FhirContext ctx = FhirContext.forR4();
String serverBase = "http://hapi.fhr.org/baseR4";
IGenericClient fhirClient = ctx.newRestfulGenericClient(serverBase);

return fhirClient.search()
.forResource(Patient.class)
.include(Patient.INCLUDE_ALL)
.where(Patient.NAME.matches().value(name))
.and(Patient.ORGANIZATION.hasId(organizationId))
.and(Patient.GENERAL_PRACTITIONER.hasId(practitionerId))
...
.count(limit)
.returnBundle(Bundle.class)
.execute()
.getEntry().stream()
.filter(entry -> entry.getResource().getResourceType().equals(ResourceType.Patient))
.map(entry -> (Patient) entry.getResource())
.collect(Collectors.toList());
}

And when we have a lot of integrations with FHIR across the project — all this boilerplate code will be repeated again and again with small differences depending on entity.

Our code would be much more clean if we will have kind of Spring Data repository but for FHIR. The code above may look like this:

List<Patient> findAllPatientsByNameAndOrganizationIdAndPractitionerIdUseLimit(String name, 
String organizationId, String practitionerId, int limit);

Or like this:

@Query("SELECT p FROM Patinet where name = {name} AND organizationId = {organizationId} AND practitionerId = {practitionerId} LIMIT {limit}")
List<Patient> findAllPatientsByFilters(String name,
String organizationId, String practitionerId, int limit);

Let’s add some Spring magic into this FHIR integration…

Next part:
Spring Data Commons implementation for HAPI FHIR (Part 3)

--

--