SMART on FHIR

Binary Data

Note: Opala’s publicly documented APIs are read-only. The guidance and examples on this page describe standard FHIR behavior on a Firely-based server for reference. Write operations and administrative server behaviors are not available on public endpoints.

In many scenarios, resources such as DocumentReference are used to store or reference large files (for example, scanned PDFs and images). These resources use the Attachment datatype, which records a MIME type (contentType) and either inline Base64 data (data) or a URL pointing to the content (url). The Binary resource can also carry a standalone payload with its own contentType and data.

Large files increase payload size when Base64-encoded, and embedding them inline can be cumbersome for clients. This page explains common strategies for handling binary content in Opala and clarifies what is available on public APIs versus what can be enabled in managed/private environments.

Externalized Binary Storage

Opala deployments (in managed or private environments) may be configured to handle binary payloads in ways that reduce database size and client payloads for large files. If you rarely handle large binaries, storing Base64 inline in Attachment.data may be simpler. For frequent or large artifacts, consider patterns that keep bytes outside the resource body and reference them from FHIR, as described below.

Note on scope: In Opala’s Firely-based FHIR implementations, there is no built-in “storage mode” switch for database blobs or filesystem buckets the way some other servers provide. Opala persists Base64 data in the FHIR database and offers a Binary wrapper for sending and receiving raw bytes over HTTP while still storing Base64 internally. For truly external storage, use the standard FHIR pattern of placing a resolvable URL in Attachment.url and managing the object in your own storage tier.

The options below describe approaches for binary storage; some are available only in managed or private Opala environments.

Binary Storage Mode: Database (Default)

By default, binary content is stored inline within FHIR resources as Base64 in Attachment.data or in a Binary.data element. This configuration is simple and portable. It is appropriate for testing and for smaller payloads because Base64 adds approximately 33 percent overhead, which increases request and response sizes for large files.

Binary Storage Mode: Database Blob

In some deployments, binary bytes are stored in a dedicated binary/BLOB column separate from the JSON resource body, while the FHIR resource (for example, DocumentReference or Binary) holds the metadata and a pointer to the stored bytes. Unlike the default inline mode, payloads are generally streamed to and from the database instead of being fully loaded into application memory, which improves performance for larger files.

If your organization adopts out-of-line storage behind the FHIR API, treat it as an infrastructure pattern:

  • Keep FHIR metadata (such as contentType, hash, size, and any tags) in the resource.

  • Store the bytes in an auxiliary store or service.

  • From FHIR’s perspective you will either:

    • continue to persist Base64 in Attachment.data or Binary.data, or

    • store the object externally and place a resolvable link in Attachment.url.

Binary Storage Mode: Filesystem

In filesystem mode (or an object store), binary bytes are written as individual files under a managed directory or bucket structure. Each file is assigned a globally unique name at create time so a shared directory (for example, a network share or cloud bucket) can be safely used by multiple nodes.

When planning such a deployment, define:

  • The base path or bucket and directory layout for stored objects.

  • Appropriate permissions and encryption at rest.

  • Backup, retention, and cleanup policies for orphaned files.

  • A stable, resolvable URL scheme to place in Attachment.url.

FHIR will treat Attachment.url as a link; access control, delivery, and lifecycle for the underlying file are responsibilities of your storage tier.

Binary Access Operations

Opala’s public endpoints do not expose vendor-specific custom operations like $binary-access-read or $binary-access-write. In managed or private Opala environments, use standard FHIR patterns with Binary and Attachment to upload, store, and retrieve bytes. Authorization and auditing apply the same way they do for other FHIR resources.

There are two common ways to move bytes:

  • Binary as JSON: Base64 in Binary.data (simple, portable).

  • Binary as raw bytes: send/receive the file directly using Content-Type and Accept (if enabled in your environment).

Writing Binary Content (Binary Resource)

Use the Binary resource when you need to persist a file as its own server-managed object, give it a stable id, and reference it from other resources (for example, from DocumentReference.content.attachment.url).

  • Choose JSON/Base64 when files are small or tooling prefers pure FHIR JSON.

  • Choose raw bytes when clients stream files and you want to avoid Base64 overhead.

  • Always set the correct MIME type in Binary.contentType (or via the Content-Type header for raw uploads).

  • Treat writes as versioned updates. If your environment returns a version ETag, include If-Match on subsequent PUTs to prevent lost updates.

Option A: Create Binary via JSON (Base64)
POST https://{baseurl}/Binary
Content-Type: application/fhir+json

{
  "resourceType": "Binary",
  "contentType": "application/pdf",
  "data": "(base64-pdf-here)"
}
Option B: Create Binary with raw bytes (if enabled)
POST https://{baseurl}/Binary
Content-Type: application/pdf

...raw file bytes...

The server creates a Binary, sets contentType from the header, and returns 201 Created with a Location.

Reading Binary Content (Binary Resource)

Read Binary when you want either the metadata plus Base64 or the exact file stream.

  • Ask for JSON to get the Binary resource with Base64 in data.

  • Ask for the file type (for example, Accept: application/pdf) to stream the raw bytes, when supported.

  • Typical errors are 404 (not found), 406 (unsupported Accept), 415 (unsupported Content-Type).

Option A: Read Binary as JSON
GET https://{baseurl}/Binary/{id}
Accept: application/fhir+json
Option B: Stream raw bytes (if enabled)
GET https://{baseurl}/Binary/{id}
Accept: application/pdf

Linking from DocumentReference

Use DocumentReference to describe the artifact (who, what, when) and link the bytes via an Attachment. This keeps metadata lightweight and lets clients decide when to fetch the file.

  • Point attachment.url to Binary/{id} when you store bytes in Binary.

  • Or point attachment.url to a secure, external URL that your storage layer controls.

  • Always set attachment.contentType to the media type of the file.

Example: DocumentReference that links to a Binary

POST https://{baseurl}/DocumentReference
Content-Type: application/fhir+json

{
  "resourceType": "DocumentReference",
  "status": "current",
  "subject": { "reference": "Patient/123" },
  "content": [
    {
      "attachment": {
        "contentType": "application/pdf",
        "url": "Binary/{id}"
      }
    }
  ]
}

Serving Raw Media Resources

The Media resource also uses an Attachment to hold image, audio, or video content. By default, reads return JSON with Base64 in Media.content.data.

  • For efficient streaming, the recommended pattern is to store bytes in Binary and set Media.content.attachment.url to Binary/{id} with the correct contentType. Clients can then GET the Binary as JSON or stream raw bytes (when enabled).

  • If you host media in an object store or CDN, place a secure, resolvable link in Media.content.attachment.url and manage access at that layer.

Some deployments enable raw-media streaming when a client sends an Accept matching the media type or a specific query flag. Opala’s public endpoints do not expose that behavior; check the environment’s CapabilityStatement or deployment notes for managed/private environments before relying on it.