Skip to main content

Bundle — Batch & Transaction

Couchbase FHIR CE supports FHIR Bundles to perform multiple operations in a single request. Endpoint (note: no resource type in the path):

Example

POST /fhir/<bucket>/
e.g. POST http://localhost/fhir/acme/
ImgBundle

JSON Body

{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:3da658f0-76ae-4ddd-94ce-4cdbb12a1e8e",
"resource": {
"resourceType": "Patient",
"id": "3da658f0-76ae-4ddd-94ce-4cdbb12a1e8e",
"identifier": [
{
"system": "http://hospital.smarthealthit.org",
"value": "MRN001"
}
],
"name": [
{
"use": "official",
"family": "Doe",
"given": ["Jane"]
}
],
"gender": "female",
"birthDate": "1970-12-01"
},
"request": {
"method": "POST",
"url": "Patient"
}
},
{
"fullUrl": "urn:uuid:ad8085ce-fbf7-442b-99e5-f9f02e7dcd92",
"resource": {
"resourceType": "Observation",
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs",
"display": "Vital Signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "85354-9",
"display": "Blood pressure panel with all children optional"
}
]
},
"subject": {
"reference": "urn:uuid:3da658f0-76ae-4ddd-94ce-4cdbb12a1e8e"
},
"effectiveDateTime": "2023-06-01T12:00:00Z",
"component": [
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8480-6",
"display": "Systolic blood pressure"
}
]
},
"valueQuantity": {
"value": 120,
"unit": "mmHg"
}
},
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8462-4",
"display": "Diastolic blood pressure"
}
]
},
"valueQuantity": {
"value": 80,
"unit": "mmHg"
}
}
]
},
"request": {
"method": "POST",
"url": "Observation"
}
}
]
}

Response - 200 OK

{
"resourceType": "Bundle",
"id": "5ab72487-9469-4240-a3a0-b418b1b1e7c3",
"meta": {
"lastUpdated": "2025-10-09T19:54:36.095+00:00"
},
"type": "transaction-response",
"timestamp": "2025-10-09T19:54:36.095+00:00",
"link": [
{
"relation": "self",
"url": "http://localhost/fhir/acme/"
}
],
"entry": [
{
"resource": {
"resourceType": "Patient",
"id": "8c350e25-1640-421b-a1e1-e6d077873728",
"meta": {
"versionId": "1",
"lastUpdated": "2025-10-09T19:54:35.974+00:00",
"tag": [
{
"system": "http://couchbase.fhir.com/fhir/custom-tags",
"code": "created-by",
"display": "user:anonymous"
}
]
},
"identifier": [
{
"system": "http://hospital.smarthealthit.org",
"value": "MRN001"
}
],
"name": [
{
"use": "official",
"family": "Doe",
"given": ["Jane"]
}
],
"gender": "female",
"birthDate": "1970-12-01"
},
"response": {
"status": "201 Created",
"location": "Patient/8c350e25-1640-421b-a1e1-e6d077873728"
}
},
{
"resource": {
"resourceType": "Observation",
"id": "e00a7f2e-1a42-446b-ba5a-9f412afc4fe2",
"meta": {
"versionId": "1",
"lastUpdated": "2025-10-09T19:54:36.050+00:00",
"tag": [
{
"system": "http://couchbase.fhir.com/fhir/custom-tags",
"code": "created-by",
"display": "user:anonymous"
}
]
},
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs",
"display": "Vital Signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "85354-9",
"display": "Blood pressure panel with all children optional"
}
]
},
"subject": {
"reference": "Patient/8c350e25-1640-421b-a1e1-e6d077873728"
},
"effectiveDateTime": "2023-06-01T12:00:00Z",
"component": [
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8480-6",
"display": "Systolic blood pressure"
}
]
},
"valueQuantity": {
"value": 120,
"unit": "mmHg"
}
},
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8462-4",
"display": "Diastolic blood pressure"
}
]
},
"valueQuantity": {
"value": 80,
"unit": "mmHg"
}
}
]
},
"response": {
"status": "201 Created",
"location": "Observation/e00a7f2e-1a42-446b-ba5a-9f412afc4fe2"
}
}
]
}

Bundle Types

type: "transaction"

  • Atomic, all-or-nothing. The server processes the entries as a single unit:
  • If all succeed → commit.
  • If any fails → none are applied; the response includes the failure.

Response: type:

"transaction-response" with one entry.response per input entry.

type: "batch"

  • Non-atomic. Entries are executed independently; some may succeed while others fail.
  • Order is server-defined (no cross-entry guarantees).

Response: type:

"batch-response" with one entry.response per input entry.

Entry Anatomy

Each entry typically has:

  • fullUrl: a temporary identifier for this entry’s resource. Commonly a URN such as urn:uuid:guid used to link entries together before real IDs exist.
  • resource: the FHIR resource payload (for methods that send a body).
  • request: the operation to perform:
  • method: POST, PUT, PATCH, DELETE, or GET
  • url: relative interaction URL such as Patient, Patient/123, Observation?code=…, etc.

URN / fullUrl resolution

Within the same bundle, you can reference another entry’s fullUrl. During processing the server:

  • Creates the resource (assigning server ID for POST).
  • Builds a mapping from fullUrl → the final canonical reference (e.g., Patient/8c350e25-…).
  • Rewrites internal references to canonical form.

In our example, the Observation’s subject.reference changes from urn:uuid:3da6… → Patient/8c350e25-1640-421b-a1e1-e6d077873728.

Processing Model

  • For transaction bundles, Couchbase FHIR CE executes the entire bundle inside a single ACID transaction over Couchbase:
  • Collect & validate entries (FHIR R4 rules, plus US Core if enabled for the bucket).
  • If validation:
    • Strict → any violation aborts the transaction.
    • Lenient → warnings logged; proceed.
    • Disabled → skip validation.
  • Resolve dependencies using fullUrl mapping and any conditional URLs (e.g., PUT Patient?identifier=…).
  • Apply each request in a safe order (e.g., create Patient before Observation that references it).
    • POST: server assigns a new UUID id.
    • PUT: preserves/sets the ID from the URL; creates or updates.
    • PATCH: applies JSON Patch (RFC 6902).
    • DELETE: soft-deletes (tombstone).
    • GET: allowed in bundles; returns the matched resource in the response entry.

Versioning & audit

  • meta.versionId increments per write.
  • meta.lastUpdated set by server.
  • meta.tag set (created-by / updated-by).
  • Prior versions copied to Resources.Versions.

Commit / rollback

  • Transaction bundles: either everything commits or everything rolls back.
  • Batch bundles: no overall transaction; each entry stands alone.

Isolation & consistency

  • Transaction bundles run with ACID semantics across the participating KV/N1QL operations.
  • Practical effect: readers won’t see partial results; writers see a consistent snapshot of documents involved.
  • No READ-UNCOMMITTED.
FTS

FTS itself is not transactional; searches reflect the committed state once the transaction completes and the index refreshes.

Response Shape

Top-level Bundle with:

  • type: "transaction-response" or "batch-response"
  • entry[]: one per input, each with:
  • response.status (e.g., 201 Created, 200 OK, 204 No Content, 404 Not Found, 412 Precondition Failed)
  • response.location (canonical location for created/updated resources)
  • Optional resource (when Prefer: return=representation or when the interaction returns a body, e.g., GET)

Our sample shows:

  • Patient created → 201 Created, location Patient/id
  • Observation created → 201 Created, with subject rewritten to the new Patient ID

Conditionals inside Bundles

You can use conditional interactions within entries:

  • Conditional PUT: PUT Patient?identifier=system|value
    • 1 match → replace; 0 → create; >1 → 412
  • Conditional PATCH: PATCH Observation?identifier=…
    • 1 match → patch; 0 → 404; >1 → 412
  • Conditional DELETE / READ similarly follow FHIR rules.
    • The server resolves conditionals as part of the transaction, so either all cross-references are fixed and applied, or none are.

Validation & Profiles

  • Base FHIR R4 validation always available.
  • If the bucket enables US Core 6.1.0, profile rules and ValueSet bindings are enforced per your Strict / Lenient / Disabled setting.
  • Failures in Strict abort a transaction bundle.

Best Practices

  • Prefer transaction when creating graph-connected resources (Patient + related Observations), so references are resolved atomically.
  • Use fullUrl: "urn:uuid:..." for intra-bundle linking; avoid guessing IDs.
  • For upserts, prefer conditional PUT with a unique identifier rather than name.
  • Keep bundles reasonable in size for performance (e.g., tens to low hundreds of entries).
  • For responses, add header Prefer: return=representation if you want the full created/updated resources echoed in each entry.resource.

Summary

  • Batch = independent operations, non-atomic.
  • Transaction = atomic ACID unit; reference rewriting, versioning, and validation all happen together.
  • fullUrl + URNs let you build self-contained graphs that the server resolves to canonical references in one step.
  • The endpoint is the bucket root (/fhir/bucket/), not a resource type.
  • Fully aligned with FHIR R4 semantics; US Core rules apply when enabled.