FHIR Messages – part 2
October 6, 2014 3 Comments
In the previous post, we talked about how we could map a relatively simple HL7 v2 message into a FHIR message. We focused on the actual mapping between the two message types, and there were a number of aspects that we didn’t consider – especially workflow & architecture.
In this post, let’s take a closer look at these considerations – perhaps in the form of a ‘checklist’ of things to consider when planning a deployment. We’ll keep the context to the simple one of a radiology result to keep the scope under control.
There’s also a whole section in the spec which talks about messaging as well. In particular there is a discussion on basic messaging assumptions and Message Exchange Patterns that we won’t repeat here – but should be reviewed before any implementation is planned.
Here’s the logical architecture (excluding Auditing & UI components):
So the “Message Processor” is the application that is taking the incoming HL7 v2 message from the Sending System and generating a FHIR message that is submitted to the Server ‘Mailbox’ endpoint that will process it, return a reply which the Message Processor will convert into a v2 response message and return to the Sending System. In this particular architecture, the communication with the Sending system is asynchronous, but with the mailbox is synchronous.
The “Server Mailbox” is the server that will store the Observation resource. It exposes a ‘mailbox’ endpoint behind which is the message processing (based on the MessageHeader.event code) which defines the type of FHIR message.
Note that although the Patient and Provider stores are shown as external to the server mailbox, they may not be – as discussed below.
Let’s summarize the overall message flow, assuming a synchronous HTTP connection from Message Processor to the mailbox.
- The sending system (perhaps a Radiology System) creates the v2 message and sends it to the Message Processor. Likely this is an Integration Engine that receives external messages for the enterprise.
- The Message Processor generates the FHIR message bundle as described in the previous post, and forwards it to the server mailbox. This processing may involve interactions with the Patient and Provider stores. Both bundle and MessageHeader are assigned identifiers – the MessageHeader.identifier representing this ‘business level’ message identifier (and came from the sending system), and the bundle ID representing this particular ‘instance’ (See Message Exchange Patterns in the spec for further details).
- The server mailbox recognises this type of message (using the MessageHeader.event code) and performs the required processing (which is discussed further below, but basically saves the Observation resource).
- When processing is complete, the mailbox creates another bundle (with a unique bundle ID) that contains a new MessageHeader and returns that to the Message Processor. The contents of the MessageHeader will reflect the characteristcs of the endpoint and will have its own unique identifier, but in particular it contains a response element that indicates that this message is a response message (equivalent to the ACK message in v2). The response element has:
- an identifier – which is the MessageHeader.identifier of the original message, and serves to link response to request unambiguously. This is not really needed in a synchronous paradigm, but certainly needed for asynchronous operation.
- a code which has a fixed set of values that indicates the outcome of the processing.
- a details element which is an OperationOutcome resource containing the details of errors or anything else the sender needs to know about.
- The Message Processor receives the response message, and constructs an HL7 v2 ACK message containing the appropriate segments (eg MSA and/or ERR segments depending on the code value, and contents of the response.details resource).
- The ACK message is returned to the original sender.
The HTTP status code will reflect the outcome of processing. Refer to the spec for details.
Architectural considerations
- Where are the Patient & Provider stores? If they are not on the same server as the Observation, then new Patient & Provider resources may need to be created by the Message Processor (unless the server endpoint can do this – see mailbox assumptions).
- How will the MessageProcessor communicate with the server? This could be a synchronous HTTP connection to the mailbox endpoint (which would allow the Message Processor to handle and server errors), or maybe some asynchronous Integration Engine / Messaging infrastructure. If asynchronous, then theMessage Processor will need to use the MessageHeader.response.identifier to link response with the original message.
- How does the Message Processor manage errors – either during message mapping or mailbox processing errors?
Server Mailbox Assumptions
This is referring to the server that will process the FHIR message that the Message Processor creates – receiving it via the mailbox endpoint as described above. It may – or may not – also host the Patient and Provider resources that we need.
- Does the mailbox actually store the Observation locally, or does it act as a proxy and store it on some other server?
- Assuming that the Patient & Provider resources are locally hosted, can the mailbox create local resources if required, and resolve the Observation resources?
- If the Patient & Provider resources are on a different server, then can the mailbox query and create resources on those external servers? It would make the Message Processor mapping simpler….
- Is there other processing that the mailbox should perform other than the saving of resources. For example, should it create some form of notification that there is a new result to review (and how should it determine who to direct the notification to, and the type of notification? Actually, that’s another question: should FHIR have a ‘notification’ or a ‘task’ resource?)
- Should the mailbox return the updated Observation in the return bundle on a successful save?
Policy questions
- What is the identifier namespace used for lookup of Patient & Provider? If there is no namespace in the v2 message, do we assume that local Patient/Provider stores should be used? (In this context, ‘local’ means the stores used by the system).
- What happens if the Patient or Provider do not already exist in the local stores? Can they be created, or is this an error condition? If an error, how should it be managed?
- What happens if there are multiple Patient/Providers with the same identifier? Is that an error (and if so, how should it be corrected), or should the Message Processor just choose one of them to use.
Message transformation questions
- What should we use for the source and destination endpoints in the message? In the previous post we simply copied them across from the v2 message, but should the source endpoint actually be the Message Processor, and the destination the server mailbox endpoint? This could be especially important if the server mailbox accepts messages from different clients as well as the Message Processor.
- Should we populate the responsible element? This might be appropriate if the result was a response to an order that is electronically recorded to allow local reconciliation. Actually, there’s some thinking needed here, especially how this relates to Order and OrderResponse resources (perhaps another post sometime…)
Well that’s a brief examination of how the workflow might operate and some things to think about. I’ll update this post as we work further in this space.
Pingback: More FHIR Messaging: ADT messages | Hay on FHIR
Pingback: The Architecture and the (FHIR) Message | Hay on FHIR
Pingback: Webinar | Hay on FHIR