Provider Directories – part 1

So I’ve been sort of following the Validated Directory track at the Connectathon in San Antonio. I say ‘sort of’ because I’m interested in the idea of using the VerificationResult resource to track the provenance of individual entries in a registry (though I’m not entirely clear about the relationship between VerificationResult and Provenance).

Update: After a chat with those who know these things, the Provenance resource indicates who actually created the resource, while the VerificationResult is who said the information was correct. So I might create a Practitioner resource with my qualifications (so the Provenance points to me) while my Medical School confirms that I do, indeed, have a medical degree – which would be the VerificationResult. And there could be multiple VerificationResults if, say, the check needed to be repeated.

The first thing to do is to set up my own directory server. The approach I’m taking is to use a ‘vanilla’ FHIR server (HAPI) as the actual data repository, with a layer in front of it to manage any specific business functionality I need. As we discussed in described in a previous post, I’m currently using Node-RED as my prototyping environment, so this is the overall architecture I’m using:

(Note that I’ve added a couple of security components that I think I’m going to need later on – more on that later).

So I started by firing up (sorry) a new instance of a DigitalOcean cloud server, and installed Node-RED and a HAPI CLI server on it. These were vanilla installs – though I did enable CORS on the Node-RED server so it can be accessed from other browser apps like clinFHIR or conMan, and I also added all the StructureDefinition files for the R4 FHIR release (as VerificationResult  is new in R4 – actually level 0 in maturity, so brand new).

Having got the environment set up, the next task is to populate it with some sample data. The Validated Directory project helpfully supplies reference servers with sample data – so the easiest approach was to ‘borrow’ some resources from one of those servers (apparently Eric Haas is the original source of the data). The easiest approach was to create a Node-RED flow to this – here’s what it looks like.

screen shot 2019-01-14 at 8.28.03 am

There are a number of interesting points about this flow.

  • Firstly, note that it doesn’t start with an http input node. Rather, there’s an ‘inject’ node that needs to be manually triggered through the Node-RED admin interface. This makes sense, as I only want to do this once (after debugging of course) – it’s an administrator function.
  • Next up is a function node that just sets the json Accept header, and then the HTTP request node itself. The request node has a hard coded url as it has a fixed value – I can use either the Aegis or the Telstra server.
  • After returning the data as a FHIR Bundle, we need to think about how to save that in the local server. There are a couple of options, but the simplest is to create a transaction bundle and submit that – that way it’s only a single call, and it will either succeed or fail as a whole. We can’t just send the bundle we received from the reference server – it’s the wrong bundle type (‘searchset’ compared to ‘transaction’) and it’s also missing the ‘request’ property in each entry that tells the target server what to do.

So the next node (a function node) does this for us. Here’s what the code looks like:

var bundle = {resourceType:'Bundle',type:'transaction',entry:[]}

//create a verifying organization
var organization = {resourceType:'Organization',id:'cfImporter'}
organization.name = 'Importer';

//and add to the bundle...
 addToBundle(organization)

msg.payload.entry.forEach(function(entry,inx){
    var practitioner = entry.resource;
    //remove root extensions (some are causing errors)
    delete practitioner.extension;
    
      
    //add an hpi identitier
    var identifer = {system:'https://standards.digital.health.nz/id/hpi-person'}
    identifer.value='hpiNumber'+inx
    practitioner.identifier.push(identifer);
    
    //add to the insert bundle
    addToBundle(practitioner)

    //create the Verification resource
    var vr = {resourceType:'VerificationResult'}
    vr.id = 'vr'+ inx;
    vr.target = {reference:'Practitioner/'+practitioner.id}
    vr.status = 'validated';
    vr.attestation = {who:{reference:'Organization/'+organization.id}}
    addToBundle(vr)
})

node.warn(bundle)
msg.payload = bundle;
return msg;

function addToBundle(resource) {
    //add a tag to all imported resources (so we can differentiate them from others)
    resource.meta = resource.meta || {}
    resource.meta.tag = resource.meta.tag || []
    resource.meta.tag.push({system:'http://clinfhir.com/tag',code:'IMPORT'})
    
    var entry = {resource:resource,request:[]}
    var request = {method:'PUT',url: resource.resourceType + '/'+resource.id}
    entry.request.push(request);
    bundle.entry.push(entry)
}

Some notes:

  • The resources all have an id assigned by the client and are updated using a PUT method. This means that the flow can be run any number of times – which is useful both in debugging, and also means that it can be extended as required – right now only Practitioner resources are being imported, but later on we’ll want more – like PractitionerRole, Organization and Location for example
  • We definitely want to add a VerificationResult  resource for each Practitioner. To do this, we create an Organization resource, and use it as the attestation node in the VerificationResult  (the target will be the Practitioner of course).
  • Each Practitioner gets a made up HPI identifier in addition to any others they may have. We’re using the New Zealand requirements as the basis of this work, so it makes sense to add it here.
  • We also add a tag meta element to every resource so we can manipulate them if necessary. For example, there’s an _tag query we could use to get them all.
  • I’m still not sure whether I should have added Provenance here as well. It would be easy enough to do – just create it and add to the bundle as with the other resources.

So that completes the import script (for now). We’ll likely re-visit it later as we add more resources, but here’s the relationships between resources as it currently stands:

screen shot 2019-01-14 at 8.39.13 am

So now we can complete the first scenario in the track (retrieve a single practitioner with associated VerificationResult. The following query will do it (scroll sideways to see the full thing):

[host]/Practitioner?identifier=https://standards.digital.health.nz/id/hpi-person|hpiNumber3&_revinclude=VerificationResult:target

Note that this uses the _revinclude (reverse include) query parameter – effectively it is saying to return the Practitioner (hopefully only 1) that has the HPI identifier of ‘hpiNumber3’, and any associated VerificationResult  resources that reference it. It’s a query – so the response will be a bundle of resources.

So that’s enough for the moment.  Next up we’ll deviate from the Connectathon script to think about exposing our own API that accesses the FHIR data through our Node-RED instance, and more closely matches what we need in New Zealand (or, at least what I think we need 🙂 ).

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.

One Response to Provider Directories – part 1

  1. Pingback: Provider Directories – part 2 | 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