Lors de la création d'un bundle à partir de données héritées, je (et d'autres) souhaitais pouvoir contrôler si les ressources étaient générées avec une méthode de requête FHIR PUT plutôt qu'avec la méthode POST codée en dur. J'ai étendu les deux classes responsables de la transformation de SDA en FHIR dans une production d'interopérabilité afin de prendre en charge un paramètre permettant à l'utilisateur de contrôler la méthode de requête.
La première classe est la classe Processus métier. Elle inclut un nouveau paramètre exposé dans l'onglet « Paramètres » de l'interface d'interopérabilité, appelé FHIRRequestMethod. Elle doit également transmettre la propriété FHIRRequestMethod à la méthode de classe de transformation en tant que paramètre.
Class Demo.FHIR.DTL.Util.HC.SDA.FHIR.ProcessV2 Extends HS.FHIR.DTL.Util.HC.SDA3.FHIR.Process
{
Parameter SETTINGS = "FHIRRequestMethod:Basic"
Property FHIRRequestMethod As %String(MAXLEN = 10) [ InitialExpression = "POST" ]
Method ProcessSDARequest(pSDAStream, pSessionApplication As %String, pSessionId As %String, pPatientResourceId As %String = "") As %Status
{
New %HSIncludeTimeZoneOffsets
Set %HSIncludeTimeZoneOffsets = 1
Set tSC = $$$OK
Try {
If '$Data(%healthshare($$$CurrentClass, "isInteropHost"))#10 {
$$$ThrowOnError(##class(HS.Director).OpenCurrentProduction(.tProdObj))
Set tClassName = ""
For i = 1:1:tProdObj.Items.Count() {
If tProdObj.Items.GetAt(i).Name = ..TargetConfigName {
Set tClassName = tProdObj.Items.GetAt(i).ClassName
Quit
}
}
Kill tProdObj
Set tIsInteropHost = 0
Set tRequiredHostBases("HS.FHIRServer.Interop.Operation") = ""
Set tRequiredHostBases("HS.FHIRServer.Interop.HTTPOperation") = ""
Set tHostBase = ""
For {
Set tHostBase = $Order(tRequiredHostBases(tHostBase))
If tHostBase="" Quit
If $ClassMethod(tClassName, "%IsA", tHostBase) {
Set tIsInteropHost = 1
Quit
}
}
Set %healthshare($$$CurrentClass, "isInteropHost") = tIsInteropHost
} Else {
Set tIsInteropHost = %healthshare($$$CurrentClass, "isInteropHost")
}
Do ..GetHostAndPort(.tHost, .tPort)
Set tLocalHostAndPort = tHost_$Select(tPort'="":":",1:"")_tPort
If ..FHIRFormat="JSON" {
Set tMessageContentType = "application/fhir+json"
} ElseIf ..FHIRFormat="XML" {
Set tMessageContentType = "application/fhir+xml"
}
Set tFHIRMetadataSetKey = $ZStrip($Piece(..FHIRMetadataSet, "/", 1), "<>W")
Set tSchema = ##class(HS.FHIRServer.Schema).LoadSchema(tFHIRMetadataSetKey)
If '..FormatFHIROutput {
Set tIndentChars = ""
Set tLineTerminator = ""
Set tFormatter = ""
} Else {
Set tIndentChars = $Char(9)
Set tLineTerminator = $Char(13,10)
Set tFormatter = ##class(%JSON.Formatter).%New()
Set tFormatter.IndentChars = tIndentChars
Set tFormatter.LineTerminator = tLineTerminator
}
#dim tTransformObj As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR
Set tTransformObj = $ClassMethod(..TransformClass, "TransformStream", pSDAStream, "HS.SDA3.Container", tFHIRMetadataSetKey, pPatientResourceId, "", ..FHIRRequestMethod)
Set tBundleObj = tTransformObj.bundle
$$$HSTRACE("Bundle object", "tBundleObj", tBundleObj.%ToJSON())
If ..TransmissionMode="individual" {
For i = 0:1:tBundleObj.entry.%Size()-1 {
If tIsInteropHost {
Set tSC = ..CreateAndSendInteropMessage(tBundleObj.entry.%Get(i), tSchema, tMessageContentType, tFormatter, tIndentChars, tLineTerminator, pSessionApplication, pSessionId)
} Else {
Set tSC = ..CreateAndSendFHIRMessage(tBundleObj.entry.%Get(i), tSchema, tLocalHostAndPort, tMessageContentType, tFormatter, tIndentChars, tLineTerminator, pSessionApplication, pSessionId)
}
}
} Else {
If tIsInteropHost {
Set tSC = ..CreateAndSendInteropMessage(tBundleObj, tSchema, tMessageContentType, tFormatter, tIndentChars, tLineTerminator, pSessionApplication, pSessionId)
} Else {
Set tSC = ..CreateAndSendFHIRMessage(tBundleObj, tSchema, tLocalHostAndPort, tMessageContentType, tFormatter, tIndentChars, tLineTerminator, pSessionApplication, pSessionId)
}
}
} Catch eException {
Set tSC = eException.AsStatus()
}
Quit tSC
}
Storage Default
{
<Data name="ProcessV2DefaultData">
<Subscript>"ProcessV2"</Subscript>
<Value name="1">
<Value>FHIRRequestMethod</Value>
</Value>
</Data>
<DefaultData>ProcessV2DefaultData</DefaultData>
<Type>%Storage.Persistent</Type>
}
}
La deuxième classe est la classe de transformation, pour laquelle nous devons également ajouter une nouvelle propriété pour stocker le paramètre FHIRRequestMethod. La valeur de FHIRRequestMethod provient de l'appel de la méthode de classe à ..TransformStream
. Une fois que ce paramètre du processus métier est passé à ..TransformStream
, je le stocke dans la propriété de classe afin que toutes les méthodes de cette classe de transformation aient accès à la valeur.
Class Demo.FHIR.DTL.Util.API.Transform.SDA3ToFHIRV2 Extends HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR
{
Property FHIRRequestMethod As %String(MAXLEN = 10)
ClassMethod TransformStream(stream As %Stream.Object, SDAClassname As %String, fhirVersion As %String, patientId As %String = "", encounterId As %String = "", FHIRRequestMethod As %String) As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR
{
set source = $classmethod(SDAClassname, "%New")
if SDAClassname = "HS.SDA3.Container" {
$$$ThrowOnError(source.InitializeXMLParse(stream, "SDA3"))
}
else {
$$$ThrowOnError(source.XMLImportSDAString(stream.Read(3700000)))
}
return ..TransformObject(source, fhirVersion, patientId, encounterId, FHIRRequestMethod)
}
ClassMethod TransformObject(source, fhirVersion As %String, patientId As %String = "", encounterId As %String = "", FHIRRequestMethod As %String) As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR
{
set schema = ##class(HS.FHIRServer.Schema).LoadSchema(fhirVersion)
set transformer = ..%New(schema)
Set transformer.FHIRRequestMethod = FHIRRequestMethod
if source.%ClassName(1) = "HS.SDA3.Container" {
do transformer.TransformContainer(source, patientId)
}
else {
do transformer.TransformSDA(source, patientId, encounterId)
}
return transformer
}
Method AddResource(source As HS.SDA3.SuperClass, resource As %RegisteredObject = "", ByRef resourceJson As %DynamicObject = "") As HS.FHIR.DTL.vR4.Model.Base.Reference [ Internal ]
{
if '$isobject(resourceJson) {
set resourceJson = ##class(%DynamicObject).%FromJSON(resource.ToJSON())
}
try {
do ..%resourceValidator.ValidateResource(resourceJson)
} catch ex {
do ..HandleInvalidResource(resourceJson, ex)
return ""
}
set entry = ##class(%DynamicObject).%New()
set entry.request = ##class(%DynamicObject).%New()
set id = ..GetId(source, resourceJson)
if id '= "" {
set resourceJson.id = id
}
set sourceIdentifier = ""
if resourceJson.resourceType = "Encounter" {
set sourceIdentifier = source.EncounterNumber
}
elseif ((source.%Extends("HS.SDA3.SuperClass")) && (resourceJson.resourceType '= "Provenance")) {
set sourceIdentifier = source.ExternalId
}
if id = "" {
if (resourceJson.resourceType = "Patient") && (..%patientId '= "") {
set id = ..%patientId
}
elseif $get(..%resourceIds(resourceJson.resourceType)) '= "" {
set id = ..%resourceIds(resourceJson.resourceType)
}
elseif (sourceIdentifier '= "") && $data(..%resourceIds(resourceJson.resourceType, sourceIdentifier)) {
set id = ..%resourceIds(resourceJson.resourceType, sourceIdentifier)
}
if id '= "" {
set resource.id = id
set resourceJson.id = id
}
}
if resourceJson.id '= "" {
set id = resourceJson.id
set entry.fullUrl = $select(..GetBaseURL()'="":..GetBaseURL() _ "/", 1:"") _ resourceJson.resourceType _ "/" _ resourceJson.id
set entry.request.method = "PUT"
set entry.request.url = resourceJson.resourceType _ "/" _ resourceJson.id
}
else {
set id = $zconvert($system.Util.CreateGUID(), "L")
set entry.fullUrl = "urn:uuid:" _ id
set entry.request.method = ..FHIRRequestMethod
set entry.request.url = resourceJson.resourceType
}
if resourceJson.resourceType = "Patient" {
set ..%patientId = id
}
elseif sourceIdentifier '= "" {
set ..%resourceIds(resourceJson.resourceType, sourceIdentifier) = id
}
set duplicate = ..IsDuplicate(resourceJson, id)
if duplicate '= "" {
return duplicate
}
set ..%resourceIndex(resourceJson.resourceType, id) = resourceJson
set entry.resource = resourceJson
do ..%bundle.entry.%Push(entry)
return ..CreateReference(resourceJson.resourceType, id)
}
}
Ces classes sont conçues pour être utilisées dans une production d'interopérabilité. La démonstration qui met en évidence la version de base de ces classes peut être trouvée ici :
Learning Services: Converting Legacy Data to HL7 FHIR R4 in InterSystems IRIS for Health & Github Repo for Legacy To FHIR Transformation Demo