Site icon Hay on FHIR

Thoughts about updating Registries

In New Zealand we are lucky enough to have had a national patient registry for some years which serves as a unique identifier of patients in New Zealand – the National Health Index or NHI. The Registry is an instance of an EMPI (Enterprise Master Patient Index) and currently  exposes a SOAP interface that can be accessed by clients across a protected network.

In order to make it available for more users we are working in a project to expose a FHIR API that will offer similar functionality to the existing SOAP one, be simpler to use, available across the public Internet and so accessible to a wider range of clients in support of the healthcare ecosystem. We’re also looking at similar work for Provider registries.

This is what the architecture will look like (at a very high level – and not including any security or audit considerations):

The API will be exposed across two networks  – the existing private network that links providers in New Zealand and the public Internet. It has three main purposes:

We had a couple of options to expose the query interface. We could have used the standard restful query API allowing searching on a number of properties but we decided to only support the identifier query (for when NHI number is known) and to implement the $match operation for querying on other properties, as this is designed for querying an EMPI. It works by having the client create a sample patient instance with the elements containing the data to search on and sending that to the API. The server then uses those elements to query the EMPI, returning a list of possible matches with the score indicating how close the match is for each patient.

The server can also apply business logic to the query enforcing the validation rules such as requiring the date of birth and gender to be present in the query.

Here’s an example used for searching for male patients named Doe, born in 1970. Note that the query is contained in a Parameters resource – which is the standard method for passing parameters when invoking operations.

{
    "resourceType": "Parameters",
    "id": "example",
    "parameter": [{
        "name": "resource",
        "resource": {
            "resourceType": "Patient",
            "gender": "male",
            "birthDate": "1970",
            "name": [{"text": "Doe"}]
        }
    }]
}

And here’s what a response might look like (abbreviated)

{
    "resourceType": "Bundle",
    "id": "26419249-18b3-45de-b10e-dca0b2e72b",
    "type": "searchset",
    "total": 1,
    "entry": [{
        "fullUrl": "http://server/path/Patient/doe1",
        "resource": {
            "resourceType": "Patient",
            "id": "doe1",
            "name": [{
                "given": ["john"],
                "family": "Doe"
            }]
        },
        "search": {
            "mode": "match",
            "score": 0.9
        }
    }]
}

It’s up to the server to decide how to perform the query and how to score it. For example it could choose to include patients born in different years and with slightly different spellings of the name – perhaps phonetic matches.

When it comes to updating patient data the situation is a little more complicated.

There are a number of strategies we could use (assuming a real-time interface):

The restful update API allows the client to create an updated patient instance and submit that to the server which then replaces the current version. This would require us to examine the submitted instance to ensure that the data is valid, that it is a permissible update, that it doesn’t change what it shouldn’t and that the current user is allowed to make this update.

The Patch API allows the client to specify only the elements that are to be changed. For example it could specify a new phone number which would replace or add to the existing ones. The client creates a small document (which can be XML, JSON or FHIRPath) which specifies the changes to make against the indicated patient resource. Here’s an example of a JSON patch that changes the patient date of birth.

[{
  "op": "replace",
  "path": "/birthDate",
  "value": "1987-12-03"
}]

And here is one that removes the patients second address

[{
  "op": "remove",
  "path": "/address/1"
}]

 

These would both be applied against the resource instance (so you need to know the resource id), eg:

PATCH [host]/Patient/100

Finally, we could define specific operations for the updates that we support. For each update use case, we define the inputs that are required, any outputs and the business logic/validation that need to be applied. The operation itself is defined in an OperationDefinition resource. The client then uses the parameters resource to package the data and send it to the operation.

In considering these options, we decided that the restful update API is overly simplistic for our needs, but choosing between patch and operations is not so obvious.

Patch is straightforward to use but does have a number of drawbacks in our use case:

There is also an architectural consideration. Both Patch and the restful update API place the control with the client. It is the client that states the exact nature of the change they want to make to the resource and the server follows that instruction (validation and security permitting) – though it can make changes to the resource. The operation however places the control with the server. The client specifies what they want to change (for example add an address) and the server makes the changes needed to meet that requirement.

For these reasons we are proposing to use operations as the primary mechanism for updating the patient resource. We’re creating specific operations scoped to each use case which can then be mapped to the usual roles permitted to invoke them.

To manage updates to repeating fields (like address) we added an id field to each array element in the patient instance that we expose. This was straightforward as all datatypes support an id field, as does the EMPI (and this is the way that the current SOAP interface works.)

Here’s the OperationDefinition for the updateAddress operation  (abbreviated).

{
  "resourceType":"OperationDefinition",
    "url":"http://hl7.org.nz/fhir/OperationDefinition/Patient-update-address",
    "status":"draft",
    "kind":"operation",
    "id":"Patient-update-address",
    "system":false,
    "type":true,
    "instance":false,
    "parameter": [
        {
            "name": "nhi",
            "use": "in",
            "min": 1,
            "max": "1",
            "type": "Identifier",
            "documentation":"The current (active) identifier for the patient that the address is to be added to"
        },
        {
            "name": "addressIdToRemove",
            "use": "in",
            "min": 0,
            "max": "*",
            "type": "string",
           "documentation":"The id of the address/s to be removed."
        },
        {
            "extension" : [
                {"url":"http://hl7.org/fhir/StructureDefinition/operationdefinition-profile",
                "valueUri":"http://hl7.org.nz/StructureDefinition/NHIAddress profile"}          
            ],
            "name": "addressToAdd",
            "use": "in",
            "min": 0,
            "max": "*",
            "type": "Address",
           "documentation":"The address/s to add. This must be a valid Address datatype conformant to the http://hl7.org.nz/StructureDefinition/NHIAddress profile"
        } ,
        {
            "name": "return",
            "use": "out",
            "min": 0,
            "max": "1",
            "type": "Resource",
           "documentation":"The updated Patient resource."
        }
    ]
  }

So we’re stating that in this operation you can:

And it’s an easy matter validate the request, and to map them to user roles for security.

BTW – we could have (and still could) apply the operation to a patient instance (as with patch) so the nhi parameter would be unneeded. But it does seem clearer this way – and all the implementers are familiar with the NHI (or should be 🙂 )

Here’s what an actual request might look like (adding a new address) to the patient with the NHI ABC1234

{
    "resourceType": "Parameters",
    "parameter": [
        {
            "name":"nhi",
            "valueIdentifier" : {
                "system":"https://standards.digital.health.nz/id/nhi",
                "value":"ABC1234"
            }
        },
        {
            "name": "addressToAdd",
            "valueAddress" : {
                "text":"23 thule st"
            }
        }
    ]
}

or, we could replace an address with a new one (a delete and an add):

{
    "resourceType": "Parameters",
    "parameter": [
        {
            "name":"nhi",
            "valueIdentifier" : {
                "system":"https://standards.digital.health.nz/id/nhi",
                "value":"ABC1234"
            }
        },
        {
            "name": "addressToAdd",
            "valueAddress" : {
                "text":"23 thule st"
            }
        },
        {
            "name": "addressIdToDelete",
            "valueString":"xxx"
        }
    ]
}

Obviously, you could (and should) include all the detailed components of the address.

If there are errors with the request – either incorrect data (like an invalid address), or a permissions mismatch then the statusCode will indicate that the operation failed, and there may be an OperationOutcome with more information about the error.

We’ve not talked in the project team about the best way to create a new Patient. As we discussed earlier, not all elements can be supplied by the client (eg identifier, generalPractitioner) and some of these will be added by the server during the create process. We could either use a normal POST operation, or another operation – the POST seems the easiest to me (there’s nothing in the spec that prevents a server altering the resource when it receives it).

Finally, here’s a screen dump of some of the operations in our project site (because each one is defined by an OperationDefinition resource it’s a straightforward matter to render them in a webpage – and to indicate valid datatypes, profiles and terminology bindings with lookup). Of course, they will also appear in the formal Implementation Guide that we will produce, along with all the other FHIR artifacts and documentation.

Do note that the operations are still under development and will definitely change before the Project is complete. Apart from anything else, we want implementer feedback into these.

Our belief is that this will be straightforward for implementers – something we’ll be testing at a connectathon of course!

 

 

 

Exit mobile version