Search

Exchange patterns

NB: This is a draft specification!

Introduction

Transaction input and output should be exchanged from one actor to ZorgDomein, and from ZorgDomein to another actor in the same transaction. The question is how this data should be exchanged between the involved systems, assuming the HTTP transport protocol. There are three relevant options:

  • Push: in this pattern, the provider of the data pushes this data to the consumer of the data directly. ZorgDomein currently uses this pattern for providing transaction documents to a recipient of a transaction: in that case it is a HTTP POST of a Bundle resource.
  • Pull: in this pattern, the provider puts the data on a server and waits for the consumer of the data to collect it. This requires the consumer to implement a polling mechanism: it should check if the server has new data on a regular basis.
  • Notified-pull: this pattern is a combination of push and pull. When a data provider has data available for the data consumer, it will put this data on a server, and it will push a notification to that data consumer to inform the consumer about that new data. Subsequently, the data consumer will pull the data from the data server at the data provider.

Providing data: notified-pull

Within the playing field of interoperability in the healthcare IT, more and more interfaces shift to an exchange pattern based on notified-pull because it combines the best of both push and pull patterns. The most important advantages of this pattern over push and pull are:

  • It is more robust than push: a push mechanism requires the data consumer to be always available. If the data consumer happens to be unavailable, the pushed data might get lost, unless the data provider decides to retry at a specific interval, hoping that the data consumer will become available again. The notified-pull mechanism enables the data consumer to check for missed data after it has been unavailable for a while. Additionally, the data provider may choose to resend a notification at a specific interval if delivery of the notification fails. Resending notifications causes less network load than resending the complete dataset.
  • It enables a more fine-grained authorization mechanism compared to push: when pushing data, the data provider should authenticate the data consumer as the rightful party to deliver the data to. In a push scenario, the data provider is a network client, and the data consumer is a network server. Assuming that an organization can delegate authentication to a network server, authentication on organization level is possible using a push pattern. However, authentication on user level is hardy possible because a person cannot reliably delegate authentication to a network server. This means that the data provider cannot reliably authenticate the data consumer when the data consumer is a person when a push pattern is used. In contrast to the push pattern, the data consumer is the network client in the notified-pull pattern. Since a network client is very suitable for user authentication, this pattern enables the data provider to authenticate the data consumer being a person. Hence the notified-pull pattern enables user level authorization.
  • It enables better network traffic distribution compared to push: it enables the data consumer to decide if it actually needs the data, and when it needs that data.
  • It saves network traffic compared to pull: a pull pattern requires a polling mechanism which can cause quite some network traffic. That disadvantage is eliminated in the notified-pull pattern, because the notification will trigger only a single pull request.
  • It saves expensive authorization processes compared to pull: the polling mechanism that is required by the pull pattern, requires the data provider to authorize the data consumer to the requested data for each request. That can be a computational expensive process. This disadvantage is eliminated in the notified-pull pattern, because the notification will trigger only a single pull request.
  • It is faster than pull: the interval of the polling mechanism required for pull may cause a delay in data exchange. The notified pull pattern allows the data consumer to instantly obtain the data as soon as it receives a notification. Based on these advantages and the shift towards the notified-pull pattern in the playing field of interoperability, the notified-pull pattern is the preferred pattern for exchanging new data.

Because of these reasons, the notified-pull exchange pattern must be applied for cases when new data is available at the data provider. Also, data updates at the data provider must be exchanged with the data consumer using this pattern.

Updating data as a data consumer: push

There will also be cases where the data consumer has one or more updates to the retrieved data at the data provider. In these cases, it is important that the data is maintained and managed at the data source. That means that updates to data that was provided by the data provider, should initially be applied at the data provider. The use of the notified-pull pattern for these updates requires a bi-directional implementation of the notified pull pattern. That could cause serious synchronization conflicts, since two opposite update notifications might cross each other. This issue becomes even more troublesome if multiple data consumers would try to update data at one data provider, which would imply a multi-directional notified-pull pattern. This issue is inherent to the principles of the pull pattern, so it disqualifies both pull and notified-pull for update actions at the data provider. Therefore, updates from the data consumer should be sent to the data provider using a push exchange pattern. This means that updates to FHIR resources at the data provider must be transmitted using a HTTP PUT request, see https://www.hl7.org/fhir/STU3/http.html#update for additional details. There are two points of attention when using this pattern:

  1. In most cases, the update concerns only one or a few attributes of the FHIR resource. However, the client (the data consumer) must supply the full resource to the FHIR server (data provider), that includes the attributes that are not touched by the update. The FHIR server should accept the full payload of the update, and it should return the same content when it is subsequently read. This may cause conflicts at either the client or the server, see the notes about transactional integrity and variations between submitted data and retrieved data in the FHIR specifications. To avoid potential issues, each update interaction should follow this pattern:
    • Before sending the update, the client requests the latest version of the resource at the server.
    • The client applies the update to the obtained resource, leaving other attributes intact.
    • The client sends the result to the server using a HTTP PUT request. When the server responds with a HTTP 409 or 412 status code, the client must try again using the same pattern.
  2. The update request of the client may cross a notification for an update to the same resource at the server that makes the update of the client obsolete, see notes on concurrency in the FHIR specifications for details. The must be avoided using the optimistic locking mechanism, i.e., conditional updates. This requires the source to always return an ETag header with each resource, which must match the value of the version id of the resource. The client must store that version id and provide this value in the If-Match header in a subsequent HTTP PUT request. If the provided value in the If-Match header does not match with the latest version of the resource at the server, the server must return a HTTP 409 status code instead of processing the update. In that case the client must request the latest version of the resource before trying to resend the update. If the client did not provide the If-Match header, the server must return a HTTP 412 status code.

Summary

Based on the principles described above, the following rules apply to the exchange pattern between the application of the initiator of a transaction, ZorgDomein and the application of the recipient:

  • Exchange of new transactions from initiator to ZorgDomein: notified-pull
  • Exchange of new transactions from ZorgDomein to recipient: notified-pull
  • Exchange of updates to transactions from initiator to ZorgDomein: notified-pull
  • Exchange of updates to transactions from ZorgDomein to initiator: push
  • Exchange of updates to transactions from ZorgDomein to recipient: notified-pull
  • Exchange of updates to transactions from recipient to ZorgDomein: push

These patterns are visualized in the sequence diagram below.

Initiator
ZorgDomein
Recipient