Dynamically create Resources based on their StructureDefinitions?

527 views
Skip to first unread message

Marc Günther

unread,
Jan 28, 2021, 12:00:44 PM1/28/21
to HAPI FHIR
Hi,

I'm quite new to FHIR and HAPI, so forgive me if I don't know something obvious.

We want to implement a conversion from our internal representation of medical data to specific FHIR resources. For this the idea is to annotate each of our internal fields with the kind of FHIR resource it corresponds to.

For example, the data field which contains a patients body weight would be annotated with the following StructureDefinition (this is from the German Covid dataset):

Once everything is annotated this way, we can write some generic conversion function, which iterates over our data, and generates the FHIR output, based on their StructureDefinitions (there will also conversion of values to be considered, but let's leave that for later).

So for example, we would like to have some Java method, which takes:
- the value of a form field, i.e. 84kg, and
- the BodyWeight StructureDefinition,

and then outputs a FHIR data record as in the example here:

As far as I understand them, the StructureDefinitions contain all the necessary information to construct data records out of them in a generic way.

Unfortunately, I have not really found any way to do this. I can read the StructureDefinitions just fine, but there seems to be no support to create actual data records from them.

All I can do at the moment, is to use the fluent API to create a data record just as the BodyWeight example above, but then everything is hard coded in my Java code. I would then need to create Java methods for every possible data type that's part of the Gecco dataset. Which seems like a lot of effort, given that the structural information is already available.

Is there anything I missed, is somebody else already doing that, or is this idea maybe ridiculous and wouldn't work anyway? What are all those StructureDefinition used for normally, and how do you create data records for them?

Thanks for any insight,
Marc

Markus Schneider

unread,
Feb 3, 2021, 9:51:25 AM2/3/21
to HAPI FHIR
Hi Marc, 

typically there is no 1:1 class-attribute mapping between your object model and the FHIR object model.
Maybe 5 attributes in your class ends up in 3 FHIR classes.

So this is typically something for an integration engine like Apache Camel.

There is a FHIR mapping language spec but i did not had time to dig into:

Hth, Markus

Marc Günther

unread,
Feb 4, 2021, 12:04:21 PM2/4/21
to HAPI FHIR
Hi Markus,

yes, that's an additional complexity. For example BloodPressure needs two values.

So the idea is that we annotate our data fields with "BloodPressure" and the path, eg. ""Observation.component:diastolicBloodPressure.value[x]", which specifies to which value inside a Resource this should be mapped to.

And yes, there will be the problem of different Units, and converting valuesets from our internal representation to the FHIR one, but all of this can be sorted out.

My current problem is, that I don't know how to create Resources with HAPI FHIR Library. I have a StructureDefinition, I have set of values, and I know where they should go in there, but I don't know how to create a Resource from these input.

For the BodyWeight example, I have done this:
public static Resource createResourceForValue(Patient patient, StructureDefinition structureDefinition, Type value, Date creationDate) {
String type = structureDefinition.getType();
if ("Observation".equals(type)) {
Observation obs = new Observation();
obs.setId(generateRandomID());
obs.getMeta().addProfile(structureDefinition.getUrl());
Identifier identifier = obs.addIdentifier();
identifier.getType().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v2-0203").setCode("OBI");
identifier.setValue(generateRandomIDentifier());
identifier.getAssigner().setReference("Organization/secuTrial");
obs.setStatus(ObservationStatus.FINAL);
obs.addCategory().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.getCode().addCoding().setSystem("http://loinc.org").setCode("29463-7").setDisplay("Body weight");
obs.getCode().addCoding().setSystem("http://snomed.info/sct").setCode("27113001").setDisplay("Body weight (observable entity)");
obs.getCode().setText("Body weight");
obs.getSubject().setReference(patient.getResourceType() + "/" + patient.getId());
obs.setEffective(new DateTimeType(creationDate));
obs.setValue(value);
return obs;
} else {
throw new RuntimeException("unhandled type: "+type);
}
}

This is a literal translation of the BodyWeight example into Java code. But of course, it would be horrible to write this kind of method for all the 68 StructureDefinitions that exist in Gecco. After all, the information is already available in the StructureDefinitions, so why hardcode it all again? It seems like a lot of manual work, where a lot of mistakes can happen, and the worst thing is, I have only constructed this from the example given, so I have no idea if I covered all edge cases.

So to summarize my problem, I'm looking for something which takes as input:
- a StructureDefinition
- a list of values with their corresponding FHIRPath
- a Patient
- and possible a date
which then produces the correct FHIR Resource.

It seems I don't understand FHIR at all, because I can find exactly nothing on this topic, yet, shouldn't everyone have this problem? People are creating Resources all the time, no? How do they do this? Do we really have to replicate all the StructureDefinitions in code?

Thanks,
Marc

Akshay Singh

unread,
Dec 28, 2022, 6:45:07 AM12/28/22
to HAPI FHIR
Hi, I am stuck in same problem. did you find any approach for this ?
if you found something, please share it will really be helpful.

Thanks,
Akash

Marc Günther

unread,
Dec 29, 2022, 6:39:26 AM12/29/22
to Akshay Singh, HAPI FHIR
No. I asked in several places, and no one seemed to understand the problem.

We ended up writing 68 copies of that method I posted below. It's absolutely horrible and a maintenance nightmare. Also we constructed those methods from the provided examples only, as there is nothing useful in the StructureDefinitions whatsoever, I don't know why they even exist. So we might have missed a few special cases. 

It took us three weeks to make all the required changes to that mess, when Gecco updated from 1.0.3 to 1.0.5. And those were just a couple easy changes. As I said, it is completely unmaintainable. But apparently that is the way it is, everything must be hardcoded, there is no way to construct something dynamically in FHIR land.

The whole implementation took like over five months and was by far the most frustrating thing I ever did as a software developer. And then we only had Gecco. If we wanted to include another fhir project, it would be another two months or so.

So, unfortunately, I don't have the answer you are looking for...

Marc

Sent from my iPhone

On 28. Dec 2022, at 12:45, Akshay Singh <akshaysin...@gmail.com> wrote:

Hi, I am stuck in same problem. did you find any approach for this ?
--
You received this message because you are subscribed to a topic in the Google Groups "HAPI FHIR" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hapi-fhir/3Aydx6uAOWs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hapi-fhir+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/hapi-fhir/0c383e79-78d4-4fa2-8780-60113919ba67n%40googlegroups.com.

Martijn Muijsers

unread,
Apr 26, 2023, 1:03:40 PM4/26/23
to HAPI FHIR
I suppose I am the next person to now ask you whether you found a better solution? :)

I am stuck with this same problem too. I have inherited a codebase with insane duplication. I would like to stay subscribed to this problem.

I hope I can post a new insight to this issue later, and if I do not post anything, if anyone sees this please feel free to ask me later whether I did.
Reply all
Reply to author
Forward
Message has been deleted
0 new messages