Easy CSV TO FHIR - InterSystems Contest
Hello everyone, I’m a French student in academical exchange for my fifth year of engineering school and here is my participation in the FHIR for Women's Health contest.
This project is supposed to be seen as the backend of a bigger application. It can be plugged into a Front End app and help you gather information from your patients. It will read your data in local and use a Data Transformation to make it into a FHIR object before sending it to the included local FHIR server.
I wanted to participate because Women's Health is a really important topic that must be discussed more. Using my work you can easily transform any CSV file into a FHIR resource to gather information from your patient on any important subject. It could be used to gather information on pregnant women, then these data ( stored in FHIR in IRIS ) could be analyzed to see if there is any problem or complication. They can also be reviewed by a doctor for example.
See [my GitHub](https://github.com/LucasEnard/Contest-FHIR) and the Open Exchange post linked to this article.
Or see the ReadMe here :
This is a full python IRIS production that gather information from a csv, use a DataTransformation to make it into a FHIR object and then, save that information to a FHIR server.
This use interop as well as FHIR.
The objective is to help people understand how easy it is to use FHIR.
I didn't have the time to create a csv about women's health, but you can easily imagine this application using a csv on Women's Health.
- 1. Contest-FHIR
- 2. Prerequisites
- 3. Installation
- 4. FHIR server
- 5. Walkthrough
- 6. Creation of a new DataTransformation
- 7. What's inside the repo
If you work inside the container, as seen in 3.3., you don't need to install fhirpy and fhir.resources.
3.1. Installation for development
Clone/git pull the repo into any local directory e.g. like it is shown below:
git clone https://github.com/LucasEnard/fhir-client-python.git
Open the terminal in this directory and run:
docker-compose up --build
This will create the IRIS Framework and the FHIR Server.
Once you are done building enter the Management portal, open the interop tab, open the Production and start it.
Now you will see that the CSV was automatically read from your local files and added to the FHIR server.
This app will periodically read any csv inside the "csv" folder and will send it to the FHIR server, doing the Data Transformation needed.
3.2. Management Portal and VSCode
This repository is ready for VS Code.
Open the locally-cloned
fhir-client-python folder in VS Code.
If prompted (bottom right corner), install the recommended extensions.
3.3. Having the folder open inside the container
You can be inside the container before coding if you wish.
For this, docker must be on before opening VSCode.
Then, inside VSCode, when prompted (in the right bottom corner), reopen the folder inside the container so you will be able to use the python components within it.
The first time you do this it may take several minutes while the container is readied.
If you don't have this option, you can click in the bottom left corner and
press reopen in container then select
By opening the folder remote you enable VS Code and any terminals you open within it to use the python components within the container.
4. FHIR server
To complete this walktrough we will use a fhir server.
This fhir server was already build-in when you cloned and build the container.
The url is
Complete walkthrough of the Python IRIS production.
5.1. Messages and objects
Objects and messages will hold the information between our services,processes and opeartions.
obj.py file we have to create a dataclass that match the csv, this will be used to hold the information before doing the DataTransformation.
In our example the organization.csv csv looks like this,
active;name;city;country;system;value true;Name1;city1;country1;phone;050678504 false;Name2;city2;country2;phone;123456789
Therefore, the object will look like this,
@dataclass # > This class represents a simple organization class BaseOrganization: active:bool = None name:str = None city:str = None country:str = None system:str = None value:str = None
msg.py file, we will have two type of request, the first one hold information of an organization before the DataTransformation and the second one can hold the information of the organization after the DataTransformation.
5.2. Business Service
bs.py file we have the code that allows us to read the csv and for each row of the csv ( so for each organization ), map it into an object we created earlier.
Then, for each of those row ( organization ) we create a request and send it to our process to do the DataTransformation.
# We open the file with open(self.path + self.filename,encoding="utf-8") as csv: # We read it and map it using the object BaseOrganization from earlier reader = DataclassReader(csv, self.fhir_type ,delimiter=";") # For each of those organization, we can create a request and send it to the process for row in reader: msg = OrgaRequest() msg.organization = row self.send_request_sync('Python.ProcessCSV',msg)
5.3. Business Process
bp.py file we have the DataTransformation, converting a simple python object holding little information to a FHIR R4 object.
Here are the steps to do a DataTransformation using embedded python on our simple organization,
# Creation of the object Organization organization = Organization() # Mapping of the information from the request to the Organization object organization.name = base_orga.name organization.active = base_orga.active ## Creation of the Address object and mapping of the information ## from the request to the Address object adress = Address() adress.country = base_orga.country adress.city = base_orga.city ### Setting the adress of our organization to the one we created organization.address = [adress] ## Creation of the ContactPoint object and mapping of the ## information from the request to the ContactPoint object telecom = ContactPoint() telecom.value = base_orga.value telecom.system = base_orga.system ### Setting the telecom of our organization to the one we created organization.telecom = [telecom] # Now, our DT is done, we have an object organization that is a # FHIR R4 object and holds all of our csv information.
After that, our mapping is done and our DT is working.
Now, we can send this newly created FHIR R4 resource to our FhirClient that is our operation.
5.4. Business Operation
bo.py file we have the FhirClient, this client creates a connection to a fhir server that will hold the information gathered through the csv.
In this example, we use a local fhir server who doesn't need an api key to connect.
To connect to it we have to use in the on_init function,
if not hasattr(self,'url'): self.url = 'localhost:52773/fhir/r4' self.client = SyncFHIRClient(url=self.url)
Now, when we receive a message/request, we can, by finding the resource type of the resource we send with our request to the client, create an object readable by the client, and then save it to the fhir server.
# Get the resource type from the request ( here "Organization" ) resource_type = request.resource["resource_type"] # Create a resource of this type using the request's data resource = construct_fhir_element(resource_type, request.resource) # Save the resource to the FHIR server using the client self.client.resource(resource_type,**json.loads(resource.json())).save()
It is to be noted that the fhir client works with any resource from FHIR R4 and to use and change our example, we only need to change the DataTransformation and the object the holds the csv information.
5.5. Conclusion of the walkthrough
If you have followed this walkthrough you now know exactly how to read a csv of a represetation of a FHIR R4 resource, use a DataTransformation to make it into a real FHIR R4 object and save it to a server.
6. Creation of a new DataTransformation
This repository is ready to code in VSCode with InterSystems plugins.
/src/python to start coding or using the autocompletion.
Steps to create a new transformation
To add a new transformation and use it, the only things you need to do is add your csv named
Patient.csv ( for example ) in the
Then, create an object in
BasePatient that map your csv.
Now create a request in
PatientRequest that has a variable
resource typed BasePatient.
The final step is the DataTransformation, for this, go to
src/python/bp.py and add your DT. First add
if isinstance(request, PatientRequest): and then map your request resource to a fhir.resource Patient.
Now if you go into the management portal and change the setting of the
ServiceCSV to add
filename=Patient.csv you can just start the production and see your transformation unfold and you client send the information to the server.
Detailled steps to create a new transformation
If you are unsure of what to do or how to do it here is a step by step creation of a new transformation :
Create the file
Patient.csv n the
src/python/csv folder and fill it with:
family;given;system;value FamilyName1;GivenName1;phone;555789675 FamilyName2;GivenName2;phone;023020202
Our CSV hold a family name, a given name and a phone number for two patients.
src/python/obj.py write :
@dataclass class BasePatient: family:str = None given:str = None system:str = None value:str = None
from obj import BasePatient @dataclass class PatientRequest(Message): resource:BasePatient = None
from msg import PatientRequest from fhir.resources.patient import Patient from fhir.resources.humanname import HumanName
src/python/bp.py in the
on_request function write:
if isinstance(request,PatientRequest): base_patient = request.resource patient = Patient() name = HumanName() name.family = base_patient.family name.given = [base_patient.given] patient.name = [name] telecom = ContactPoint() telecom.value = base_patient.value telecom.system = base_patient.system patient.telecom = [telecom] msg = FhirRequest() msg.resource = patient self.send_request_sync("Python.FhirClient", msg)
Now if you go into the management portal and change the setting of the
ServiceCSV to add
filename=Patient.csv you can just stop and restart the production and see your transformation unfold and you client send the information to the server.
7. What's inside the repo
The simplest dockerfile to start a Python container.
docker-compose up to build and reopen your file in the container to work inside of it.
Config file if you want to debug.