Da Vinci Health Record Exchange (HRex)
0.2.0 - STU R1 - 2nd ballot

Da Vinci Health Record Exchange (HRex), published by HL7 International - Clinical Interoperability Council. This is not an authorized publication; it is the continuous build for version 0.2.0). This version is based on the current content of https://github.com/HL7/davinci-ehrx/ and changes regularly. See the Directory of published versions

Exchanging with FHIR REST

This page summarizes all of the FHIR simple RESTful actions that are not covered by search or operation pages. There are three primary patterns for simple RESTful interactions - the pull pattern, the push pattern and the asynchronous pattern. Each RESTful action will support either push or pull and might also support asynchronous.

pull

In this mode, the data consumer is the initiator. It executes a GET HTTP command against a specified endpoint on the data source. The data source then returns the requested data. The main difference between this pattern and search is that this simple pattern only returns a single matching resource, rather than a Bundle of possible matches.

Data ConsumerData Source1a. GET url1b. response containing requested resource/version

If successful, the response is an HTTP 200, along with the requested resource instance. If there is a failure, an appropriate HTTP error code will be provided, along with an optional OperationOutcome.

push

There are many RESTful actions that follow this same basic pattern. A resource of some type (or a set of deltas from an existing resource) is transmitted from data source to data consumer using a simple REST command and the appropriate endpoint. The data consumer either stores the data as requested (and acknowledges that success with an appropriate HTTP code) or it rejects the request. If accepted, a new 'version' of the resource is persisted at the specified endpoint and can potentially be referenced by other resources or subsequently queried or further manipulated. This basic pattern is shown in the diagram below:

Data ConsumerData Source1a. POST/PUT/PATCH resource/Bundle1b. HTTP 200/201 (possibly with result resource/Bundle)

async

This pattern is used for a subset of the push scenarios. The request goes from the data source to the data consumer, but the requested action does not complete immediately. Instead, the data consumer delivers the response later. The data source polls to see what the results are. This will be most commonly used with the Bundle-based actions which are processing multiple actions at once and may take longer than the HTTP time-out window allows. (Note: In theory, it would be possible to use async for pull transactions like read or vread. However no known use case exists for these simple operations to happen asynchronously.

Data ConsumerData Source1a.Request data (POST/GET) indicating desired info with Prefer=respond-async1b.HTTP 202 Accepted w/ [polling location]loop2a.GET [polling location]2b.202 Accepted (w/ optional X-Progress header)3a.GET [polling location]3b.200 Ok w/ Json Response object listing [output file locations]4a.GET [output file location]4b.[output file]

Step 1: The invocation of the RESTful action asynchronously is identical to synchronous invocation, with the exception that the Prefer header is set to "respond-async". (Note that the server is not obligated to respect the client's stated preference - it could still respond synchronously.) The response includes a location-header that identifies where to monitor for the progress of the asynchronous request.

Step 2: The data source polls the location specified in step 1 to see if the operation is complete. So long as it is not, it gets back a 202 Accepted HTTP response, possibly with a message indicating the degree of progress. (Note: At any point, the data source could also cancel the action, though cancellation of a state-changing action is not guaranteed).

Step 3: Once the action is complete, the response to the data source's polling request changes to a 200 and conveys other information, including URLs to the location of the file (or files) that contain the results of the action.

Step 4: The data source retrieves the identified file or files from the data consumer, giving it confirmation of whether the requested action was successful.

Actions

The following sections describe the different RESTful actions and indicate which pattern (or patterns) they follow.

RESTful read

read follows the pull pattern and uses a GET of the form [base]/[resourceType]/[id]. If successful, the data consumer will receive the current version of the specified resource from the data source. Asynchronous is not expected to be relevant.

Version-specific read (vread)

vread also follows the pull pattern and uses a GET of the form [base]/[resourceType]/[id]/_history/[version]. If successful, the data consumer will receive the specified version of the resource with the specified id from the data source. Asynchronous is not expected to be relevant.

RESTful create

A create follows the push pattern and uses the POST HTTP command to the [base]/[resourceType] endpoint to transmit a single resource from the data source, causing it to be stored on the data consumer. If successful, the requested record will be persisted at the RESTful endpoint with a reliable id, potentially allowing it to be queried or referenced in subsequent exchanges. The creation can be made conditional on the absence of specified data using the If-none-exist header. The response might include a copy of what was actually stored (which could be different than what was transmitted), an OperationOutcome with any warning or information messages, or just the metadata indicating id and the version created. While asynchronous use is theoretically possible, it would be uncommon for a create to take so long that synchronous operation was not possible.

RESTful update

A update follows the push pattern and uses the PUT HTTP command to the [base]/[resourceType]/[id] endpoint to transmit a single resource from the data source, causing it to be stored on the data consumer with the specified resource id. This is typically done to replace an existing version of the resource, but it can also be used to create a brand new record if there was no prior resource at that location and the data consumer permits. Some servers might also support conditional update using the [base]/[resourceType]?[search parameters] URL to create or update a resource where the id is unknown.

If successful, the requested record will be persisted at the RESTful endpoint with the specified id, potentially available to be queried or referenced in subsequent exchanges. The response might include a copy of what was actually stored (which could be different than what was transmitted), an OperationOutcome with any warning or information messages, or just the metadata indicating id and the version created by the update. The update can be made conditional on the specified id being unchanged since last accessed, using the If-match header. While asynchronous use is theoretically possible, it would be uncommon for an update to take so long that synchronous operation was not possible.

The workflow for update may be a bit more complex with a search happening prior to the update, particularly if conditional updates aren't supported.

Using Patch

Patch works identically to update, with the exception that rather than sending the whole resource as the body, the data source only sends a differential with what is believed to be the current version of the resource. The content transmitted is either a JSON Patch, XMLPatch or FHIRPath Patch. The pattern, URLs, and supported headers, as well as the potential responses are the same as for Update.

Executing batches

Processing a batch follows the Push pattern, though the Asynchronous pattern is also appropriate in some cases. The Bundle with type 'batch' is POSTed to the [base] endpoint. The response will also be a Bundle, this time with a type of 'batch-response'. There is no paging capability for batches, though obviously a data source could choose to transmit multiple small batches rather than a single 'big' batch. Because there are no dependencies between elements within a batch, size can be adjusted as need-be. (Though if actions are dependent on prior results, those would have to be sent in a separate batch - one where the previous results can be determined before submitting the second batch.)

Executing batch searches

A 'search' batch is the same as any other type of batch. It is just that in a search batch, all the requested actions are different types of search. Each entry in the batch-response will itself be a search-set Bundle. It is possible to do paging on the search-set responses within the Bundle, but paging is on a per search-set basis, not on a Bundle basis. (It is however possible to submit a new batch where each of the entries are a request for the 'next' set of results from some or all the previous queries.)

There is nothing to stop someone from submitting a transaction of searches, but there is little point because, by definition, a search cannot be interdependent on other resources and there is nothing to roll back in the event of a failure. Thus, using transaction incurs needless cost.

Executing transactions

Processing a transaction is much the same as processing a batch. The main differences are that the input must be a 'transaction' Bundle and the response will be a 'transaction-response'. The behavior is the same - the primary difference is giving guidance to the server on what sort of processing to perform, and the fact that a transaction response cannot contain failure entries.

Sharing documents

When manipulated RESTfully, creating or updating a document simply uses the create or update process with a base endpoint using the Bundle endpoint. There main difference is that the Bundle must adhere to the rules for a FHIR document. However, in addition to being stored RESTfully, FHIR documents can be transported other ways - by email, FTP, USB stick, etc. In some environments they might also be persisted as a Binary if they are being stored alongside PDFs and other non-FHIR documents. In such cases, a DocumentReference might be created alongside the Binary to provide searchable metadata to help locate the document. (DocumentReference can also be used when the document is stored as a Bundle rather than a Binary.)

Sharing collections

Like documents, creating or updating a collection simply uses the create or update process with a base endpoint using the Bundle endpoint. (Documents and collections are stored in the same place). However, unlike documents, which can be queried by chaining into their Composition resource, there are limited mechanisms to search on the content of a 'collection' Bundle without defining custom search parameters. Also, like documents, FHIR collections can also be transported in other ways such as email, FTP, USB stick, etc. They are not, however, typically stored as Binary instances or referenced by DocumentReference, though such uses are not prohibited.