文章
· 8 hr 前 阅读大约需 6 分钟

FHIR 实践

FHIR是标准,是规范,使用FHIR使大家可以使用同一种语言、语义进行交流,名称、API都是统一的,只要符合FHIR标准,任何系统都可交互。对业务开发者来说,大部分接口交互的定义交给FHIR来处理,效率大大提高。

学习FHIR首先是一个再学习的过程,这个过程对有业务开发基础的人员来说要有个入门,这个入门就是FHIR的各个结构定义的含义,以及与业务系统数据以及接口的对照关系。

FHIR需要用到的几个工具:

 

InterSystems IRIS对于 FHIR相关内容的开发,带来了极大的便利性,里面自带一套定义好的FHIR服务器,也就是包含了FHIR定义的资源及其操作方法。

我这里选用的是最新版本的InterSystems IRIS 2024,做了传统业务系统中科室、医院、病人信息、就诊信息的FHIR转换,主要过程如下:

1. 安装InterSystems IRIS

2. 配置FHIR 服务器

3. 在HIS数据库(IRIS2022)上写一个Restful API 接口,做为对外的统一出口

// w ##class(src.rest.inif).HttpOut({})
ClassMethod HttpOut(Para As %Library.DynamicObject, Type = "1") As %Library.DynamicObject
{
  new (Para,Type)
  s valueType=$classname(Para)
  if (valueType="%Library.DynamicArray"){s Param=[]}
  if (valueType="%Library.DynamicObject"){s Param={}}
  s iter=Para.%GetIterator()
  while iter.%GetNext(.key , .srcKey ) {
    d Param.%Set(key,srcKey)
  }
  s retObj={}
  if ($classname(Param)="%Library.DynamicObject") {
    return:(Param.%Size()=0) {}
  }else {
    s Param=##class(%Library.DynamicObject).%FromJSON(Para)
  }
  set httpReq=##class(%Net.HttpRequest).%New()
  set httpReq.HTTPVersion="1.1"
  set httpReq.Timeout=5
  set httpReq.SocketTimeout=10
  if (Param.Port="443") {s httpReq.Https=1
    s httpReq.SSLConfiguration="ISC.FeatureTracker.SSL.Config"
  } else {s httpReq.Port=Param.Port}
  ;b ;http1                                                                                                                                                                                           
  s httpReq.Server=Param.Server
  
  //表头
  if ((Param.%IsDefined("Header"))&&(Param.Header.%Size()>0)){
      set iter = Param.Header.%GetIterator()
      while iter.%GetNext(.key , .value ) {
        do httpReq.SetHeader(key,value)
     }
  }
  //参数
  if ((Param.%IsDefined("Param"))&&(Param.Param.%Size()>0)){
      set iter = Param.Param.%GetIterator()
      while iter.%GetNext(.key , .value ) {
        do httpReq.SetParam(key,value)
     }
  }
  if ($classname(Param.EntityBody)="%Library.DynamicObject") {
    do httpReq.EntityBody.Write((Param.EntityBody).%ToJSON())   
  }

  ;b ;http2
  if '(Param.%IsDefined("type")) {s Param.type="Post"}
  if (Param.type="Get") {
    set sc=httpReq.Get(Param.Url)
    ;b ;httpget
  }
  if (Param.type="Post") {
    set sc=httpReq.Post(Param.Url,0)
  }
  if (Param.type="Put") {
    ;w "put"_Param.Url,!
    set sc=httpReq.Put(Param.Url)
  }
  if (Param.type="Patch") {
    
    set sc=httpReq.Patch(Param.Url)
  }
  if (Param.type="Delete") {
    set sc=httpReq.Delete(Param.Url)
  }
  
   
  ;B ;httpsc
  if sc=1 { 
    if Type="1" {
      set retObj=httpReq.HttpResponse.Data.Read()
      if $classname(retObj)="%Library.DynamicObject" {
        set retObj=##class(%DynamicObject).%FromJSON(retObj)
      }else{
        return retObj
      }
    }
    if Type="2" {
      ;b ;aa2
      set retObj=httpReq.HttpResponse.Data.Read()
    }
    if Type="3" {set retObj=httpReq.HttpResponse
      ;B ;3
    }
  }else {q "0:网络不通"}
  ;b ;comhttp
  ;set retObj=$zconvert(retObj,"I","UTF8")
  s httpReq=""
  b:retObj="Service Unavailable"
  q retObj
}

4. 做一个对象与FHIR转换程序。(目的是以后将HIS里面的数据转换为FHIR

5. 整理FHIRJSON对象:通过Forge或是网站https://hl7.org/FHIR/R4B/resourcelist.html,把FHIR 定义的资源中的各个数据元素内容转换为对象的定义。在整理的过程中我们总结了下面四点要注意的地方:

  1. FHIR规范里有部分内容是多级的,而我们的业务一般都是平级,如病人信息里的地址(address)
  2. FHIR 规范里定义的valueSetcodesystem,就是对应我们日常理解的代码表。
  3. 对于业务内容的部分,我们先整理医院、科室信息,再整理病人信息、就诊信息。
  4. 对于我们现有业务系统的主键或是关联外键值,在FHIR里面可以放在identifier面,做为查询的条件或指向

6. 从HIS业务库里把职业、医院等代码表数据组成JSON对象,与FHIRJSON对象做对照并上传FHIR服务器

7. 再把病人信息和就诊信息从HIS业务库取出数据组成JSON对,与FHIRJSON对象做对照并上传FHIR服务器

 

下面是一个地址(address)字段组成的json格式例子。

"telecom": [
       {"system": "other","value": "PAPMIMobPhone"}],
    "address": [
      {
        "use": "home",
        "type": "both",
        "line": ["aaaa"],
        "state":"PAPMICTProvinceDR",
        "city": "PAPMICityAreaDR",
        "district": "Rainbow",
        "state": "PAPMICTProvinceDR",
        "postalCode": "3999",
        "period": {
          "start": "1974-12-25"
        }
        
      },

 

在这里面以FHIR对象为基准,HIS对象名放在值里面。用一个统一的方法把HIS里的对象转换成FHIR 格式 JSON对象。转换完后上传到FHIR服务器:

  while iter.%GetNext(.key , .value ) {
    s ret=##class(src.comm.comm).objToObj(value,target)
    ;if (value.CTLOCStartTime<value.CTLOCEndTime){set ret.status="inactive"}else{set ret.status="active"}
    s conObj={"resource":"Patient","EntityBody":(ret),"Param":{"identifier":(value.PAPMINo)}}
    s tmpObj=##class(src.comm.comm).operateDataFhir(conObj)
    if (tmpObj.code=1){
      s ret=##class(%DynamicObject).%FromJSON(tmpObj.data)
      d retArr.%Push(ret)
    }
    ;d retArr.%Push(value)
  }
  
  
  

 

转换示例

// 根据对照做对象转换
// s ret=##class(src.comm.comm).objToObj(src,target)
ClassMethod objToObj(src, target) [ Language = objectscript ]
{
  
  
  n (src, target)
  ;s retObj=target
  s iter=target.%GetIterator()
  s valueType=$classname(target)
  if (valueType="%Library.DynamicArray"){s retObj=##class(%Library.DynamicArray).%New()}
  if (valueType="%Library.DynamicObject"){s retObj=##class(%Library.DynamicObject).%New()}
  while iter.%GetNext(.key , .srcKey ) {
    if ($classname(retObj)="%Library.DynamicArray"){d retObj.%Push(srcKey)}
    if ($classname(retObj)="%Library.DynamicObject"){d retObj.%Set(key,srcKey)}
    
    s valueType=$classname(srcKey)
    if ((valueType="%Library.DynamicArray")||(valueType="%Library.DynamicObject")){
      s temp=##class(src.comm.comm).objToObj(src,retObj.%Get(key))
      d retObj.%Set(key,temp)
    }else{
      //为字符时
      IF ($l(srcKey,"---")>1){
        s srcKey=$replace(srcKey,"---","")
        if (src.%IsDefined(srcKey)){
          if (src.%Get(srcKey)=""){d retObj.%Remove(key)}
          else{d retObj.%Set(key,src.%Get(srcKey))}
        }else{
          d retObj.%Remove(key)
        }
      }else{
        if (src.%IsDefined(srcKey)){
          if (src.%Get(srcKey)=""){d retObj.%Set(key,"空")}
          else{ d retObj.%Set(key,src.%Get(srcKey))}
        }
     }
    }
  }
  return retObj
}

 

进行查询

 

可以看到查出了两个符合查询条件的病人。

讨论 (1)1
登录或注册以继续