SanteDB FHIR Implementation
Unlike CDRs which use FHIR as the basis of their data storage throughout the stack, SanteDB treats FHIR as an edge messaging format. Therefore FHIR resource requests are considered transient and are never persisted into the database.
Because of this, there are several implementation notes which are important to remember when interacting with the SanteDB FHIR service handlers.
Resource URLS and ID
When submitting a FHIR bundle, each entry in the bundle may contain a fullUrl
property which point to an absolute URL where the resource originated and/or was referenced. For example:
In SanteDB this fullUrl is replaced with the internal URL on the SanteDB server once submitted. For example, after submission Patient/3
would carry a fullUrl
of http://santedb_server/fhir/Patient/95569551-5abd-4484-be52-4c6986c4beb7
and an id
of 95569551-5abd-4484-be52-4c6986c4beb7
.
The FHIR message processor only tracks http://example.com/fhir/Patient/3
in order to resolve references within the same message transaction, this is not stored in the database unless the identifier is a UUID in which case the id
element will be used as the suggested UUID for inserting the patient (i.e. update if the UUID exists, or use the UUID if it doesn't).
There are several reasons that SanteDB doesn't store this information:
The
fullUrl
may be a fully qualified URL, may be an OID, a UUID, or a relative URL which have different semantic meanings in the iCDR instance.It is nearly impossible to determine if any random client is sending
id
from the perspective of itself (i.e. my internal reference for this record is X and I am sharing it with the server), or if it is from the perspective of the iCDR (i.e. I have fetched this resource from you and am using your identifier).Simple structured identifiers and fullUrls have no concrete meaning , for example
SYSTEM_A
sending aPatient
with a relative URL ofPatient/1
andSYSTEM_B
sendingPatient/1
. The actual record being updated cannot be reliably resolved with ID1
or evenPatient/1
so mis-identification is a serious risk.While it would be possible to store the
fullUrl
for an object stored as a bundle, objects submitted via simplePOST
operations via REST to the SanteDB iCDR instance would not have this contextual identifier, and would merely carry anid
element, making referencing the object impossible.
The behavior of the logical id and full URL are aligned with the FHIR behaviors specified on Logical ID , it is recommended that production deployments use business identifiers when referencing objects in FHIR.
Offsite Resource Links
In FHIR, it is possible to link to clinical data hosted offsite, or on another server. There are several reasons why this is a bad practice:
Internal processes within SanteDB wouldn't have information necessary to action the object (such as matching, de-duplication, etc.)
There would be no way for the dCDR instances to actually acquire the information to populate the user interface since offsite references assume that an internet connection is available to fetch the resource
There is an assumption made that the offsite server will be accessible at all times from all clients which may consume the information, this is often not the case.
There is a dependency on another system to be present, the identifier / resource to be valid (not removed as part of a merge/move operation, etc.)
Consider the following request to create a patient
When submitting this resource to the SanteDB FHIR interface, you will receive an error indicating that the managing organization is not known to SanteDB.
You can resolve this by either including the organization information in the submission:
Or you can manually register the Organization using the REST api and then including the logical identifier as the resource link or UUID within SanteDB's database:
FHIR References
In FHIR a Reference
object is used to link two resources together in a role. This is similar to SanteDB's EntityRelationship
class, with the limitation that EntityRelationship
does not permit the linking of objects which are not stored within the SanteDB instance.
Reference By UUID
Referencing an object by UUID is the most preferred mechanism of resource referencing. Resources which are linked by UUID are first cross referenced in the current processing scope (the bundle), followed by database linkage. Reference by UUID is commonly represented as:
Alternately, if you're not picky about what the reference type is (i.e. it could be any entity, but it is a known entity to SanteDB) you can use a plain UUID reference:
You can also reference contained resources using a local reference:
Business identifier references are also supported by the reference resolver:
Reference Bundle Object
Referencing an object which is being processed within the same scope is also permitted. The reference is subject to the following limitations:
The
reference
property must exactly match thefullUrl
property in the bundleThe
reference
objects must exist in order , i.e. aRelatedPerson
which has a reference ofPatient/1
must exist after thePatient
withfullUrl
ofPatient/1
in the bundleNo circular references are permitted (i.e.
Patient/2
withlink
toRelatedPerson/1
with a link toPatient/1
which in-turn links toPatient/2
)
Re-Submission of Unidentified Resources
Whenever a client system submits an unidentified resource to the SanteDB iCDR FHIR interface, SanteDB will create a new copy of that resource and generate a unique UUID for it. An unidentified resource is a resource which lacks any of:
A full UUID as the
id
element of the resourceA business identifier in the
identifier
element of the resource within a uniquely generated identity domain
For example, consider the registration of a patient and a related person:
Upon sending this bundle to the server, the iCDR will create a new Patient
(example: Patient/UUIDA
) and a new Person
(example: Person/UUIDB
) which is related via an EntityRelationship
. If a client re-submits this exact bundle, the iCDR will (once again) register a new Patient
(example: Patient/UUIDC
) and a new Person
(example: Person/UUIDD
).
If, however only one of the resources contained a reliable identifier, such as the patient in this example:
Then the behavior is modified such that an initial submission results in a Patient
with business identifier FHR-4040
(example: Patient/UUIDA
) and a Person
(example: Person/UUIDB
) related to one another via an EntityRelationship
.
If the client resubmits this bundle, the CDR is able to cross-reference the Patient
(as it has a business identifier of FHR-4040
) and would perform an update (on Patient/UUIDA
) however since the RelatedPerson
cannot be reliably referenced to a known object, a new Person
would be created (example: Person/UUIDC
) related to the Patient
via an EntityRelationship
.
The end state of this message would be:
Patient/UUIDA
exists with business identifierFHR-4040
Person/UUIDB
exists and is related viaEntityRelationship
as theMOTHER
ofPatient/UUIDA
Person/UUIDC
exists and is related viaEntityRelationship
as theMOTHER
ofPatient/UUIDA
The recommended manner to submit this bundle would be to either give both Patient
and RelatedPerson
a reliable business identifier:
Or to give each a UUID as their identifier:
Last updated