Site icon Hay on FHIR

FHIR Prototyping with Node-RED – part 2

In part one of this series, we looked at using node-RED to manage notifications using the FHIR Subscription resource for a Use Case where relatives (or other care givers) could be notified when a person is admitted to hospital. We looked at the overall flow – now let’s look a bit deeper into some of the details.

First up – when we received a POSTed resource, we validated that it was correct using a sub-flow. How does that work? A subflow is simply a flow that implements a specific bit of functionality and can be called by another flow. It can return one or more messages – or not have a return at all. It’s a way of ‘encapsulating’ complexity and making the main flows simpler. We could have also created a custom node for this – which has the advantage that it’s easier to re-use in many different flows, and we can use any nodejs capability.

Here’s the sub flow:

As you can see, it has exactly the same components as the main flow (though the lines are dashed). There are 2 special nodes that correspond to the ‘interfaces’ exposed by the subflow:

If you look back at the main route, you can see how these fit in.

The flow is pretty simple: first, we check that we got a valid JSON object – failing the validation if not. The function node that performs the check will add an ‘isValid’ flag to the message, and the next node is a switch that routes based on that flag. It will also create a url that will call the $validate operation on the FHIR server – which is picked up by the next node – an HTTP request node. This node makes the actual call (a POST) to the FHIR server and validates the resource.

After the HTTP request has completed, we examine the OperationOutcome resource that was returned for any errors in a function node – setting a flag and passing to the switch node as we did when checking the json. The switch then connects to the ‘valid’ or ‘invalid’ output as appropriate. (Remember that the statusCode from the $validate operation does not indicate whether the validation succeeded or failed – that information is in the OperationOutcome).

At the moment we only use this subflow when receiving a new resource via a POST – but we could easily use it in a PUT update operation as well.

Subscription

Now let’s take a look at the Subscription resource. The key parts of this resource for our purposes are:

It’s important to note that we aren’t implementing  ‘generic’ subscription functionality here. We’re being highly specific about the subscriptions – and the format of those subscriptions – that we will accept. There’s nothing to stop us relaxing that restriction – though we’d need to change the implementation design if we did so. Indeed, this is the main purpose for using node-RED for this kind of investigation – it makes it much easier to make changes like this as we are exploring and clarifying the requirements.

Although we store the subscriptions as FHIR resources, internally we use a simpler format to make checking for subscriptions easier. There’s another sub-flow for this – it reads all the Subscription resources from the FHIR server and converts them into the internal format. It gets called automatically at startup – and also when a new Subscription resource is POSTed.

Note that we aren’t looking for updates to the Subscription at the moment (such as stopping it, or changing the notification channel). It would be quite simple to do – we would support a PUT endpoint for updates, and if the resource is a Subscription just call the ‘load subscriptions’ subflow.

HL7 Version 2

So far we’ve been assuming that the PAS system in the hospital is generating Encounter resources – but it’s far more common that it generates HL7 Version 2 messages. Can we consume those as well? As it turns out we can, and here’s the flow:

We assume that the PAS system can easily POST a standard HL7 v2 message to the hub (We can always use a different input node if not). This will be a text file (though the segment endings are just a line feed) so we look to see if it’s an admission message (ADT^A01) and if it is, look for Subscriptions as we did before. We can re-use the same notification channel as we did for Encounter resources, but there is a catch – in our Subscription we had the criteria as Encounter?patient={patientId}, and we don’t have a FHIR patient id in a V2 message.

But we do have an identifier – PID-3 – so a criteria of Encounter?patient.identifier={identifier} will work for us (this is an example of a chained query by the way…) Note that we could use the same pattern for Encounter resources – but we would have to retrieve the patient resource from the FHIR server first – so it’s rather more complex to do so.

As always we could do more with this flow – for example, we could convert the ADT message into an Encounter resource and save in the FHIR server. Or – given that ADT messages also have other clinical data like Conditions and Allergies, we could create and save resources of those types as well.

User Interface

The last thing to think about is how to support a web based User Interface. For example, to create a new subscription, modify an existing one or to view notifications that have been sent (assuming we kept a history of course). Or – we talked about a Portal in the first post, any reason why it can’t be exposed from node-RED?

Turns out it’s pretty straightforward.

Given the node-RED is developed on nodejs, all you need to do is to create the artifacts that make up the application and then serve them as static files via an http input node.

Here’s the flow:

It starts (of course) with an http node listening at an appropriate end point (/ui in this case), uses a function node to create the filename for the file that has the html for that page, then a file read node before returning the file in the http response.

The flow does show a new node – the ‘catch’ node – which is triggered if a file does not exist (i.e. it’s an unknown url) in which case we set an appropriate error message and return a 404.

So there you go. Reasonably complex workflow implemented in a way that is (I think) easy to follow, easy to alter and easy(ish) to debug (breakpoints would be nice). I think if you were going to implement security – like SMART – for the user interface or API you’d delegate that to an external service and just check for access tokens on the http calls (you can insert express middleware functions to do this).

Just what you need when testing out an Implementation Guide that is more than just data structures.

 

 

 

Exit mobile version