Introduction¶
FHIR solutions are built from a set of modular components called “Resources”. These resources can easily be assembled into working systems that solve real world clinical and administrative problems at a fraction of the price of existing alternatives. FHIR is suitable for use in a wide variety of contexts – mobile phone apps, cloud communications, EHR-based data sharing, server communication in large institutional healthcare providers, and much more.
Getting Started¶
Installation¶
Pact.Fhir is compatible with .NET Standard 2.0.
You can install the packages via nuget
https://www.nuget.org/packages/Pact.Fhir.Core
https://www.nuget.org/packages/Pact.Fhir.Iota
UML¶
To get an abstract idea how the FHIR project is organized you might want to take a look at the design UML. It can be opened on draw.io https://github.com/PACTCare/Pact.Fhir/blob/master/docs/FHIR_Core_Design.xml
Working with the Core¶
Right now the core is more or less a code skeleton, that will grow over time. The documentation will be expanded as needed.
The intend is, that interactors know all needed business rules to handle a FHIR operation. Therefore they will orchestrate all actions needed. Given that they are not tightly coupled to a data source, interactors are able to work with different ones. It is up to you to either use the IOTA implementation or implement your own FhirRepository.
Implementing your own FhirRepository¶
If you decide to start using the FHIR core with your own data source, what you need to do, is to implement the FhirRepository. For the sake of simplicity the documentation will use the in memory solution below:
public class InMemoryFhirRepository : FhirRepository
{
public InMemoryFhirRepository()
{
this.Resources = new List<DomainResource>();
}
public List<DomainResource> Resources { get; }
/// <inheritdoc />
public override async Task<DomainResource> CreateResourceAsync(DomainResource resource)
{
var resourceId = Guid.NewGuid().ToString("N");
this.PopulateMetadata(resource, resourceId, resourceId);
this.Resources.Add(resource);
return resource;
}
/// <inheritdoc />
public override async Task<DomainResource> ReadResourceAsync(string id)
{
var resource = this.Resources.FirstOrDefault(r => r.Id == id);
if (resource == null)
{
throw new ResourceNotFoundException(id);
}
return resource;
}
}
Creating a resource¶
var interactor = new CreateResourceInteractor(new InMemoryFhirRepository());
var response = await interactor.ExecuteAsync(new CreateResourceRequest { Resource = resource });
Reading a resource¶
var interactor = new ReadResourceInteractor(new InMemoryFhirRepository());
var response = await interactor.ExecuteAsync(new ReadResourceRequest { ResourceId = "yourfhirresourcelogicalid" });
Working with IOTA and FHIR¶
If you are not familiar with tangle.net (https://github.com/Felandil/tangle-.net) and IOTA you might want to read a little about it before starting here.
Working with resources¶
In the IOTA context, all resources are stored as restricted MAM streams where each resource has its own stream. Resources are assigned the first 64 chars of the corresponding MAM root as a logical/version id upon creation or alteration.
Keys and Channels¶
Since access to the MAM streams is restricted, the repository has to keep track of all channels. To get you started the below linked in memory solution should be enough. Anyway you will want to write your own implementation that stores such information in a trusted data storage.
Serialization¶
The resource payload is stored as a serialized JSON or XML depending which serializer implementation you favour. If JSON/XML is not what you are looking for, you can implement your own serializer by impelemting the IFhirTryteSerializer interface.
Code example¶
The IOTA FHIR repository is coupled to the tangle.net IOTA REST implementation.
var repository = new IotaFhirRepository(IotaResourceProvider.Repository, new FhirJsonTryteSerializer(), new InMemoryResourceTracker());
var creationInteractor = new CreateResourceInteractor(repository);
var response = await creationInteractor.ExecuteAsync(new CreateResourceRequest { Resource = resource });
var readInteractor = new ReadResourceInteractor(repository);
var response = await readInteractor.ExecuteAsync(new ReadResourceRequest { ResourceId = createdResource.Id });