Article
· Oct 25, 2023 6m read

Using FHIR Adapter to offer FHIR services on legacy systems - Posting a Resource

In the previous article we saw how we could recover a resource stored in the database of our particular HIS, so today we will see how we can add new records in our HIS whose origin is an FHIR resource that we receive in our system.

CRUD operations with FHIR

One of the main functionalities of FHIR is its support for CRUD operations through the Rest API, this implies that any system that works with FHIR must provide support for HTTP calls of the GET, POST, PUT and DELETE types. For our article today we will see how we can manage a POST call to our endpoint configured automatically when installing FHIR Adapter.

If we review the FHIR specifications for resource storage calls we will see that it tells us that the URL with which we will make the call must follow this format:

http(s)://server_url/{endpoint}/{Resource}

For our example we will not use secured calls, so we will have a URL like this:

http://localhost:52774/Adapter/r4/Patient

Since what we want is to record a new patient, we must make a POST call with our patient's data in the body of the call. In our case the call format will be application/fhir+json although we could use XML format with application/fhir+xml without any problem.

Saving our Patient resource

In the previous article we were already able to see the definition of the Patient resources, so we will not repeat it here, what we are going to see is what our formatted test patient would look like. This will be our patient:

{
    "resourceType": "Patient",
    "address": [
        {
            "city": "SALAMANCA",
            "line": [
                "CALLE LAMENTOS 2 1ºA"
            ],
            "postalCode": "45021"
        }
    ],
    "birthDate": "1988-01-23",
    "gender": "F",
    "identifier": [
        {
            "type": {
                "text": "NHC"
            },
            "value": "803987"
        },
        {
            "type": {
                "text": "DNI"
            },
            "value": "87654321F"
        }
    ],
    "name": [
        {
            "family": "SANZ LÓPEZ",
            "given": [
                "REBECA"
            ]
        }
    ],
    "telecom": [
        {
            "system": "phone",
            "value": "699850017"
        },
        {
            "system": "email",
            "value": "rebek1988@hotmail.com"
        }
    ]
}

As you can see, it is a Resource of type Patient that will be what we send from our Postman to the endpoint of our server:

Great, we have received a 200 and our patient has been registered in our HIS, let's take a look at how our Patient table looks:

There we have Rebeca perfectly recorded in our HIS with the identifier that we received in the response to our POST request. Let's now go to our production to see what path our FHIR message has traveled within IRIS.

Working with the Patient resource in IRIS

So far we have seen how we can send an FHIR resource to the endpoint of our server, let's see how we translate the FHIR resource received and transform it to insert it into our particular HIS.

Let's remember how we have our production configured:

Our message will arrive through InteropService and will be forwarded to ProcessFHIRBP, where FromAdapterToHIS will be invoked to perform the corresponding operation. Let's now see the trace of the received message.

Here we can see the details of the message received, as you can see, we have received the HTTP POST request to the Patient endpoint, we also see that QuickStreamId has a value, indicating that our message is contained within a Stream.

What is our BO going to do with this message?

elseif (requestData.Request.RequestPath [ "Patient")
  {
    if (requestData.Request.RequestMethod = "POST")
    {
      If requestData.QuickStreamId '= "" {
        Set quickStreamIn = ##class(HS.SDA3.QuickStream).%OpenId(requestData.QuickStreamId,, .tSC)
        
        set dynamicPatient = ##class(%DynamicAbstractObject).%FromJSON(quickStreamIn)

        set sc = ..InsertPatient(dynamicPatient, .response)
      }      
    }
    elseif (requestData.Request.RequestMethod = "GET")
    {
      set patientId = $Piece(requestData.Request.RequestPath,"/",2)
      set sc = ..GetPatient(patientId, .response)
    }

  }

Very simple, with the information available from the request received we can redirect the message to the appropriate method, we verify that it is a specific request from the Patient resource and that the method has been POST, therefore we will recover the Stream that stores the message and we will transform it to a %DynamicObject, below we will deal with it from the InsertPatient method, let's see the code of said method:

Method InsertPatient(dynamicPatient As %DynamicAbstractObject, Output patient As Adapter.Message.FHIRResponse) As %Status
{
  Set tSC = $$$OK
  kill pResp
  set pResp=$$$NULLOREF
  set sqlInsert="INSERT INTO his.patient (name, lastname, phone, address, city, email, nhc, postal_code, birth_date, dni, gender) values (?,?,?,?,?,?,?,?,?,?,?)"
  //perform the Insert
  set tSC = ..Adapter.ExecuteUpdate(.nrows, sqlInsert, dynamicPatient.%Get("name").%Get(0).%Get("given").%Get(0), dynamicPatient.%Get("name").%Get(0).%Get("family"), dynamicPatient.%Get("telecom").%Get(0).value, 
    dynamicPatient.%Get("address").%Get(0).%Get("line").%Get(0), dynamicPatient.%Get("address").%Get(0).%Get("city"), dynamicPatient.%Get("telecom").%Get(1).value, dynamicPatient.%Get("identifier").%Get(1).value, 
    dynamicPatient.%Get("address").%Get(0).%Get("postalCode"), dynamicPatient.%Get("birthDate"), dynamicPatient.%Get("identifier").%Get(2).value, dynamicPatient.%Get("gender"))

  set sql="SELECT id, name, lastname, phone, address, city, email, nhc, postal_code, birth_date, dni, gender FROM his.patient WHERE nhc = ?"
  //perform the Select
  set tSC = ..Adapter.ExecuteQuery(.resultSet, sql, dynamicPatient.%Get("identifier").%Get(1).value)
  
  If resultSet.Next() {
    set personResult = {"id":(resultSet.GetData(1)), "name": (resultSet.GetData(2)), 
        "lastname": (resultSet.GetData(3)), "phone": (resultSet.GetData(4)), 
        "address": (resultSet.GetData(5)), "city": (resultSet.GetData(6)),
        "email": (resultSet.GetData(7)), "nhc": (resultSet.GetData(8)),
        "postalCode": (resultSet.GetData(9)), "birthDate": (resultSet.GetData(10)),
        "dni": (resultSet.GetData(11)), "gender": (resultSet.GetData(12)), "type": ("Patient")}
  } else {
    set personResult = {}
  }
  
  //create the response message
  do patient.Resource.Insert(personResult.%ToJSON())
	
	Return tSC
}

Well, as you can see, the first thing we do is execute an insert on the Patient table of our HIS (we will assume that someone has previously ensured that said patient does not exist), with the insertion completed we will execute a SELECT on the same table to obtain the identifier generated for this patient and be able to return it to the client application that sent us the request. To complete the response message we can recover the fields that we consider most relevant.

With the patient data recovered we will return to our BP which will carry out the necessary transformations to generate a Patient type resource that we can return to the client.

You can consult the transformation in the previous article.

Once the resource is generated, we will transform it into a Stream that we will include in our response and return it to the client application:

As you can see, it is really simple, we only need to retrieve the data from the patient resource and insert it into its corresponding table. Finally, we will return the registered object in the same way as we did with the GET request.

In the next article we will see how to treat a Bundle or set of resources. Thank you for your attention!

Discussion (1)1
Log in or sign up to continue