Skip to content

FHIR API

Blaze exposes a FHIR RESTful API under the default context path of /fhir. The CapabilityStatement exposed under /fhir/metadata can be used to discover the capabilities of Blaze. Everything stated there can be considered to be implemented correctly. If you find any discrepancies, please open an issue.

Interactions

Instance Level

Type Level

System Level

Operations

The following Operations are implemented:

Asynchronous Requests

Some requests like $evaluate-measure or complex FHIR searches with _summary=count can take longer as a typical HTTP request response cycle should be open. Typical HTTP request timeouts from client and intermediates are 30 seconds. Requests that take longer than that would require special handling. In oder to overcome that synchronous request handling, FHIR specifies Asynchronous Request Patterns.

Blaze implements the Asynchronous Interaction Request Pattern from FHIR R5.

Example FHIR Search Request

To initiate a sync request, the HTTP header Prefer has to set to respond-async:

sh
curl -svH 'Prefer: respond-async' "http://localhost:8080/fhir/Observation?code=http://loinc.org|8310-5&_summary=count"

The response will look like this:

text
HTTP/1.1 202 Accepted
Content-Location: http://localhost:8080/fhir/__async-status/DD7MLX6H7OGJN7SD

The status code 202 indicates that the request was accepted and will continue to be processed in the background. The Content-Location header contains an opaque URL to a status endpoint.

NOTE

Please be aware that Blaze will respond synchronously if the response is available in time or the async handling isn't implemented yet. Clients always have to be able to handle synchronous responses as well.

Polling that status endpoint:

sh
curl -svH 'Accept: application/fhir+json' "http://localhost:8080/fhir/__async-status/DD7MLX6H7OGJN7SD"

will either result in a intermediate result like this:

text
HTTP/1.1 202 Accepted
X-Progress: in-progress

or in the final response:

text
HTTP/1.1 200 OK
Content-Type: application/fhir+json;charset=utf-8
Content-Length: 412

The response itself will be a Bundle of type batch-response:

json
{
  "resourceType": "Bundle",
  "id": "DD7MLX6JYN54OHKZ",
  "type": "batch-response",
  "entry": [
    {
      "response": {
        "status": "200"
      },
      "resource": {
        "resourceType": "Bundle",
        "id": "DD7MLX6JZHGD5YSA",
        "type": "searchset",
        "total": 1689,
        "link": [
          {
            "relation": "self",
            "url": "http://localhost:8080/fhir/Observation?code=http%3A%2F%2Floinc.org%7C8310-5&_summary=count&_count=50"
          }
        ]
      }
    }
  ]
}

Cancelling an Async Request

Async requests can be cancelled before they are completed:

sh
curl -svXDELETE "http://localhost:8080/fhir/__async-status/DD7MLX6H7OGJN7SD"

Paging Sessions

Interactions and operations that return a large list of resources support paging via Bundle resources. The various Bundle resources are interlinked via the next link. Type-level searches additionally provide a previous link for backwards navigation. The process of retrieving a part of or all Bundle resources (pages) of a large response forms a paging session. Paging sessions have the following properties:

Stable

Paging sessions operate on a stable database snapshot. Next and previous links point to custom paging session endpoints. Those links expire in order to constrain the usage of a paging session (see Expire). That also means that clients which have access to a paging session, will be able to access resources that were deleted or changed after the session started, for as long as their paging links stay valid.

Expire

Paging links expire because the encryption key their page ID was encrypted with is rotated out of the key set (see Encrypted). A paging link stays usable for at least three hours and is guaranteed to be unusable five hours after it was handed out.

Every page response carries freshly encrypted links, so a session that is paged continuously renews itself. Only links that are left unused expire.

For searches issued via POST, the query params are additionally kept in the page store. Its entries expire after the duration given by PAGE_STORE_EXPIRE (one hour by default) without being accessed, and every page request of the session refreshes them.

Fast

Paging sessions don't require initial setup time and show constant costs per page in most cases. In fact paging sessions don't require book keeping at server side at all. Their state is solely communicated via link URLs. For search requests with more than one parameter, page costs can vary because of internal query handling.

Encrypted

The variable part of paging URLs is encrypted to ensure confidentiality and integrity of the paging parameters. Confidentiality is important in case some of the original query parameters contain sensitive information. To mitigate the risk of exposing this data, FHIR searches are often executed via POST requests, which helps prevent sensitive information from being logged in URLs. Consequently, it is essential that paging URLs do not reveal any confidential data. Integrity is important, because it should not be possible to manipulate the paging URL in order to access a different paging session.

Encryption Key Management

Key Rotation
Encryption keys are rotated every hour. At most three keys are stored at any time. A new key is first added as a non-primary key, becomes the primary key used for encryption on the next rotation and is only removed three rotations after it stopped being primary. That way a page ID stays decryptable for at least three and at most five hours after it was created.
Storage
Currently, encryption keys are stored in plain text within the admin database. While these keys are not accessible via an API, they are also not encrypted with an external key encryption method.
Future Improvements
Implementing external key encryption is feasible but would require additional infrastructure. If you believe that key encryption is necessary, please open an issue for further discussion.

Backwards Navigation

Type-level search results additionally contain a previous link, allowing clients to page backwards through a result set. Because paging sessions keep no server-side state (see Fast), the previous link encodes the chain of preceding page positions. To keep paging URLs bounded in size, this chain is limited to the most recent 10 pages. When paging back further than that, the previous link is omitted; use the first link to jump to the start of the result set instead.

Absolute URLs

Blaze has to generate absolute URLs of its own in links and Location headers. By default Blaze assumes to be accessible under http://localhost:8080. The environment variable BASE_URL can be used to change this.

Besides the static BASE_URL setting, Blaze also respects the reverse proxy headers X-Forwarded-Host, X-Forwarded-Proto and Forwarded to generate its base URL dynamically.