Bundles
Bundles are a fundamental concept in FHIR, serving as containers for sets of resources. While Bundle is technically just another resource type, it has unique characteristics that make it special. Bundles are primarily used to facilitate the exchange of resource collections. For example, you will often encounter Bundles when performing a search interaction. In such cases, the server responds with a Bundle. Bundles are also used in other scenarios where FHIR requires the exchange of resource lists, as detailed in the Bundle documentation.
Reading a Bundle
A Bundle includes metadata, such as its type and, in cases of search or history interactions, a total property indicating the number of results. The individual resources within a Bundle are stored in the Bundle.Entry property.
Each entry in a Bundle contains a Entry.FullUrl field, which holds the fully qualified URL identifying the resource. Since the SDK cannot determine the specific resource type in an entry, the Entry.Resource field is typed as the base class Resource. To access resource-specific fields, you need to cast the Resource to its actual type, similar to working with choice elements:
foreach (var e in result.Entry)
{
if (e is Patient p { Active: true })
{
// Output the fully qualified URL of the resource:
Console.WriteLine("Full URL for this Patient resource: " + e.FullUrl);
// Example: Output the patient's last name from the first name element:
Console.WriteLine("Patient's last name: " + p.Name[0].Family);
}
}
Creating a Bundle
The properties you need to set when creating a Bundle depend on its intended use case. For instance, if you are a server developer constructing a search result, you must include the Bundle.total property. Similarly, when creating a transaction, you need to specify the HTTP operation for each resource entry in the Bundle.
To add resources to a Bundle, you can populate the Entry list with EntryComponent instances. Each EntryComponent includes the resource and its fully qualified URL. Alternatively, you can use the AddResourceEntry method of the Bundle class, which simplifies the process when only the URL and resource are required. For more complex scenarios, manually creating EntryComponent instances may be more appropriate.
Here is an example demonstrating both approaches:
var collection = new Bundle();
collection.Type = Bundle.BundleType.Collection;
// Adding the first entry manually
var first_entry = new Bundle.EntryComponent();
first_entry.FullUrl = $"{res1.ResourceBase}{res1.ResourceType}{res1.Id}";
first_entry.Resource = res1;
collection.Entry.Add(first_entry);
// Adding a second entry using AddResourceEntry
collection.AddResourceEntry(res2, "urn:uuid:01d04293-ed74-4f93-aa0a-2f096a693fb1");
In this example, we create a Bundle of type Collection, and for this kind of Bundle we need to make sure all resources have a FullUrl. The first resource, res1, already has a technical ID (Resource.Id). We construct its FullUrl using information from the resource instance, though the ResourceIdentity helper methods in the Hl7.Fhir.Rest namespace could also be used.
The second resource, res2, is new and does not yet have Resource.Id, so we generate a temporary one.
Creating a Transaction Bundle
Constructing Bundles manually, as demonstrated earlier, can be tedious. To simplify this process, the SDK offers a TransactionBuilder class, which streamlines the creation of batch and transaction Bundles.
Creating a transaction Bundle involves three key steps:
Instantiate a
TransactionBuilder, specifying the appropriate “base address” (typically the server’s address you are interacting with) and the type of Bundle to create, such astransaction,batch, or any other relevant Bundle type for batches.Add one or more operations to the transaction by invoking the corresponding batch methods (
Update,Create,Delete, or evenSearch).Call the
ToBundle()method to generate the final transaction Bundle.
The following example demonstrates how to create a batch transaction that atomically updates res1 and creates a new resource res2:
var tb = new TransactionBuilder("http://example.org/fhir", Bundle.BundleType.Batch);
tb.Update(res1);
tb.Create(res2);
var transactionBundle = tb.ToBundle();
