1. Bundle Resources
Bundle is a container containing many Resources. It is how FHIR handles multiple resources in one request, packages documents, and returns search results.
Bundle Types
| Type | Description | Use cases |
|---|---|---|
| searchset | Search results | Response of GET search |
| transaction. transaction | Atomic operations group | Create many related resources |
| batch. batch | Operations independent group | Bulk operations, each entry processed independently |
| document. document | FHIR Document | Clinical document (Composition + resources) |
| message. message | FHIR Message | Messaging paradigm (MessageHeader + payload) |
| collection | Collection | Pool resources without specific interactions |
| history. history | History changes | Response of _history |
| subscription-notification | Subscription notice | Real-time notifications |
2. Transaction Bundle
Transaction Bundle handling atomic — all successful entries or all rollbacks.
For example: Create Patient + Encounter + Observation at the same time
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:patient-temp-1",
"resource": {
"resourceType": "Patient",
"name": [
{
"family": "Nguyễn",
"given": ["Văn", "A"],
"text": "Nguyễn Văn A"
}
],
"gender": "male",
"birthDate": "1990-05-15",
"identifier": [
{
"system": "http://hospital.vn/mrn",
"value": "MRN-2025-001"
}
]
},
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=http://hospital.vn/mrn|MRN-2025-001"
}
},
{
"fullUrl": "urn:uuid:encounter-temp-1",
"resource": {
"resourceType": "Encounter",
"status": "in-progress",
"class": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code": "AMB"
}
]
}
],
"subject": {
"reference": "urn:uuid:patient-temp-1"
},
"period": {
"start": "2025-01-15T08:00:00+07:00"
}
},
"request": {
"method": "POST",
"url": "Encounter"
}
},
{
"fullUrl": "urn:uuid:obs-temp-1",
"resource": {
"resourceType": "Observation",
"status": "final",
"category": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "vital-signs"
}
]
}
],
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "8310-5",
"display": "Body temperature"
}
]
},
"subject": {
"reference": "urn:uuid:patient-temp-1"
},
"encounter": {
"reference": "urn:uuid:encounter-temp-1"
},
"valueQuantity": {
"value": 37.2,
"unit": "°C",
"system": "http://unitsofmeasure.org",
"code": "Cel"
}
},
"request": {
"method": "POST",
"url": "Observation"
}
}
]
}
Conditional References in Transaction
Use urn:uuid: Make a temporary ID so that entries in the same transaction refer to each other. The server will replace it with the actual ID after creation.
Transaction Response
{
"resourceType": "Bundle",
"type": "transaction-response",
"entry": [
{
"response": {
"status": "201 Created",
"location": "Patient/patient-001/_history/1",
"etag": "W/\"1\"",
"lastModified": "2025-01-15T08:00:00Z"
}
},
{
"response": {
"status": "201 Created",
"location": "Encounter/encounter-001/_history/1",
"etag": "W/\"1\""
}
},
{
"response": {
"status": "201 Created",
"location": "Observation/obs-001/_history/1",
"etag": "W/\"1\""
}
}
]
}
Transaction Processing Rules
- Server processes in order: DELETE → POST → PUT/PATCH → GET (conditional)
- All entries must succeed → atomic
- If any entry fails → All transaction rollbacks
urn:uuid:references are resolved before processing
3. Batch Bundle
Batch processing independent — Each entry is processed separately, a failed entry does not affect other entries.
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{
"request": {
"method": "GET",
"url": "Patient/patient-001"
}
},
{
"request": {
"method": "GET",
"url": "Observation?subject=Patient/patient-001&category=vital-signs&_sort=-date&_count=5"
}
},
{
"request": {
"method": "GET",
"url": "Condition?subject=Patient/patient-001&clinical-status=active"
}
},
{
"request": {
"method": "GET",
"url": "MedicationRequest?subject=Patient/patient-001&status=active"
}
}
]
}
Use case: Get all patient information in one API call instead of 4 separate calls.
Batch Response
{
"resourceType": "Bundle",
"type": "batch-response",
"entry": [
{
"resource": {"resourceType": "Patient", "id": "patient-001", "...": "..."},
"response": {"status": "200 OK"}
},
{
"resource": {"resourceType": "Bundle", "type": "searchset", "...": "..."},
"response": {"status": "200 OK"}
},
{
"resource": {"resourceType": "Bundle", "type": "searchset", "...": "..."},
"response": {"status": "200 OK"}
},
{
"resource": {"resourceType": "OperationOutcome", "...": "..."},
"response": {"status": "404 Not Found"}
}
]
}
4. Compare Transaction vs Batch
| Characteristics | Transaction | Batch |
|---|---|---|
| Atomicity | ✅ All-or-nothing | ❌ Independent |
| Internal references | ✅ urn:uuid: resolved | ❌ Not supported |
| Failure handling | Full rollback | Each entry returns its own status |
| Performance | Slower (transaction boundary) | Faster (parallel possible) |
| Use cases | Related data, needs consistency | Batch reads, independent writes |
5. Mixed Operations in Transaction
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"request": {
"method": "PUT",
"url": "Patient/patient-001"
},
"resource": {"resourceType": "Patient", "id": "patient-001", "active": true}
},
{
"request": {
"method": "DELETE",
"url": "Observation/obs-old-001"
}
},
{
"request": {
"method": "POST",
"url": "Observation"
},
"resource": {"resourceType": "Observation", "status": "final"}
},
{
"request": {
"method": "GET",
"url": "Condition?subject=Patient/patient-001",
"ifNoneMatch": "W/\"5\""
}
}
]
}
6. Summary
Bundle — Container for many resources, 8 different types
Transaction — Atomic, all-or-nothing, use urn:uuid: for internal references
Batch — Independent processing, parallel, each entry returns its own status
Transaction is suitable for data integrity, Batch is suitable for performance. performance