FHIR Prototyping with Node-RED – part 1

As FHIR continues to mature, one of the things we’re seeing is a move away from ‘simple’ data representation Implementation Guides to more complex ones that describe a workflow of some sort. Compare, for example the Argonaut data query Implementation Guide with the Argonaut scheduling guide currently in development. The scheduling guide has got a lot of workflow components to it.

As you will know, a large part of the FHIR ethos is the practical testing of these guides before they are finalized to ensure that they are fit for purpose – often at a Connectathon. But to implement guides like this often requires a significant amount of coding – especially for the server. Is there a simpler way that these guides can be tested?

In this post, I’ll talk about one possibility – using the Node-RED application to develop a prototype server which can quickly be altered as testing occurs.

Designed primarily for the IOT market, Node-Red (NR) is a graphical tool that allows you to ‘wire together’ services, applications, JavaScript code and devices into ‘flows’ that represent specific business use cases. It’s nowhere near as feature rich as Integration Engines like Rhapsody or Cloverleaf, but it is very easy to use and being a web application based on nodejs it is very extensible.

Whether you’d use it in a high volume production setting – particularly in healthcare – is debatable, especially as the monitoring functions are minimal compared with their Integration Engine brethren, but it’s a great tool for quickly building up a working solution – perfect for testing an Implementation Guide (and maybe incorporating a small pilot).

To test this out, I chose a simple use case that uses FHIR notifications to let relatives know when a person is admitted to hospital. In more detail:

  1. A FHIR subscription is created where a relative subscribes to Encounter events for a given person.
  2. That person is admitted to a hospital.
  3. The hospital (via its Patient Administration – PAS system) emits a message that is sent to the NR hub.
  4. The hub notifies the relative that the person has been admitted.

Of course, there’s a lot more detail you would go into for a real implementation, but given that I just want to see if NR will work out, it’s enough of a start.

Here’s the architecture:

arch

The idea is that node-RED acts as a ‘proxy’ interface to a standard FHIR server (like HAPI for example) – that can store any resource. We’re interested in Encounters and Subscriptions at the moment, but it’s easily extensible for other resources and requirements. The user (at the bottom) creates a subscription resource for a person (it might be themselves or a relative) and specify where the notification should go (the subscription channel). For example, the person might have a chronic illness and live alone, and wants their children to know when are admitted so that they can look after their home and pets by having an email sent to them.

When the person is admitted to hospital, the PAS sends an Encounter resource to the FHIR server via the node-RED hub (so, conveniently, the FHIR server has a list of all the encounters). The hub detects that there is a subscription for that encounter, and sends out the notification. It also exposes a FHIR API that allows a portal to access the resources on the server – there might be more details of the admission for example.

There’s a lot of documentation on node-RED on the web (including a set of lectures) so I won’t duplicate all that stuff. Basically, you start the app (you can download it yourself to run locally or on a server you control – or use a cloud hosted solution like FRED), create a new flow, then add nodes to the flow and wire them together as required. Messages then flow between the nodes along the ‘wires’. There is a standard set of nodes that comes with node-RED – but there’s a community library of nodes and flows available – and you can also create your own nodes if needed.

Let’s start with a simple example – providing a ‘proxy’ API for retrieving resources from the FHIR server. By routing the call through node-RED, we can perform other functionality  such as authenticating the caller, or providing an access audit trail.

Here’s what the flow looks like:

1. get proxy

There are 4 nodes in this flow (excluding the comment flow) and the message passes from left to right between them.

The first is an HTTP node that accepts a GET request to the endpoint ‘/fhir/’. This is relative to the url to the node-RED instance, but you can set it to anything you want.

Next up is a ‘function’ node. This allows you to add any javascript you want that will operate on the message it receives (as well as context and other stuff). In this case we are taking in the request from the HTTP node, and generating a request to the FHIR server. Here’s the code:

 

//extract the components of the URL (It's a GET)
//message is in format /fhir/{resourcetype}?{query param}&{query}
// or /fhir/{resourcetype}/id

var remoteFhirServer = global.get('remoteFhirServer')
var ar = msg.req.originalUrl.split('/');
ar.splice(0,2); //remove the "/fhir"
var query = remoteFhirServer + ar.join('/')
msg.url = query;        //the HTTP request node will execute this url
return msg;

 

As you can see it is a simple script – it looks up the root for the remote FHIR server using a global object (there’s another node that sets this up), then gets the submitted url from the ‘msg’ object (which represents the incoming message), and creates a FHIR query for the next node which it saves on the ‘url’ property of the message. The ‘req’ property on the ‘msg’ object is the nodejs request – so you can access any part of it you need).

Now we have an ‘adjusted’ query, we can actually call the FHIR server and retrieve the matching resources. Other than the path, we haven’t altered the query at all so it can be anything that the FHIR server supports (which in the case of HAPI is pretty much anything).

And in the final node, we take the response from the server and return it to the original caller.

Note that this is a very simple flow – there’s much more that we could do, like:

  • Look for an authorization token in the message, and reject if not authorized
  • Create an AuditEvent resource to record the access
  • Apply privacy rules
  • Apply any specific business logic required
  • Change the structure of the resource – maybe to convert from one FHIR version to another, or to declare conformance to a given profile.
  • Generate access statistics

Now, let’s look at a more complex flow – when a system (like the PAS system) POST’s a resource to the hub.

2. post

Again the flow is from top left to right (Actually, I do think that putting arrow heads would make it more obvious – but it’s still pretty readable).

We accept the resource using an HTTP node as before.

Next, we pass it off to a validate node. This is implemented as a ‘sub flow’ (which we’ll look at in more detail later) which takes in the message (containing the resource) and has 2 outputs:

  • The top output (there’s a popover in the app) will emit the message if it passes validation. In this case the flow continues.
  • The bottom one receives the message if it fails. In this case we return the error to the caller (using the http response node) and the flow stops.

Assuming that validation has succeeded, we save the resource to the FHIR server using a ‘set Url’ function node and an HTTP request node and return the response to the caller. The HTTP request node makes an HTTP call from the flow to an external server.

Note that there are 2 wires leading from the HTTP request node – one is the response to the caller, but the other continues the flow. In this situation, the message passes down both of them.

Continuing with the flow, we next check that the save was successful. If it was, then we check the resource type.

  • If it’s a Subscription, then we invoke the ‘Load subscriptions’ sub flow. We’ll talk about the details of the subscriptions in the next post, but in this implementation we’re saving all the subscriptions as objects in memory. This is an approach that won’t scale that well – but it’s fine for what we want to do – and we can always make it more scalable if we needed to.
  • If it’s an Encounter we examine the resource to see if it will trigger any of the subscriptions using a javascript function node. The output of the subscription check then (which basically looks for Encounter resources where the patient is the person being admitted) goes to a switch node, which routes the message to the appropriate notification mechanism – either a rest hook or an email in this implementation.

So that’s the overall implementation approach for the ‘subscription checker’. There’s more that we could do – for example:

  • Create an AuditEvent or Communication on the FHIR server to record that we sent a notification
  • Check that the notification actually succeeded (currently we just assume that it does) and have some sort of follow up action

In the next post we’ll dive into some of the details, specifically:

  • How does the validation sub flow work
  • What does the Subscription resource look like, and how did we implement it in the checker
  • Can we accommodate HL7 version 2 messages (instead of expecting the PAS to send us encounter resources
  • How can we expose a User Interface – eg for creating the subscriptions

 

 

About David Hay
I'm an independent contractor working with a number of Organizations in the health IT space. I'm an HL7 Fellow, Chair Emeritus of HL7 New Zealand and a co-chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the FHIR standard. I'm the author of a FHIR training and design tool - clinFHIR - which is sponsored by InterSystems Ltd.

4 Responses to FHIR Prototyping with Node-RED – part 1

  1. Pingback: FHIR Prototyping with Node-Red – part 2 | Hay on FHIR

  2. Pingback: Provider Directories – part 1 | Hay on FHIR

Leave a Reply

Discover more from Hay on FHIR

Subscribe now to keep reading and get access to the full archive.

Continue reading