作者

Sales Engineer at Intersystems
文章 Jeff Liu · 4 小时 前 8m read

InterSystems IRIS 中高级程序化 FHIR 执行:深入探讨 ObjectScript 集成

简而言之:InterSystems IRIS for Health 允许开发人员直接在后端 ObjectScript 例程中执行 FHIR CRUD 操作,而无需依赖 HTTP REST 层。通过使用 HS.FHIRServer.Service,开发人员可以创建服务上下文、构建动态查询、验证模式,并高效地检索 FHIR 资源。 

传统的 FHIR 实现通常通过 HTTP/REST 管道处理请求。本文探讨了绕过该层、直接在 IRIS 后端执行 FHIR 操作时的情况,重点介绍了该方法涉及的架构、服务上下文、查询处理、验证和资源访问。 

本文适用对象:本指南专为InterSystems IRIS for Health、HealthShare 和 Health Connect 开发人员,以及需要在不依赖外部 HTTP 端点的情况下,直接在后端 ObjectScript 例程中执行低开销 FHIR 操作的医疗信息学工程师而设计。

核心架构:标准流程与编程执行

部署在 InterSystems IRIS for Health、HealthShare 和 Health Connect 上的标准 FHIR 实现,依赖于通过 REST 应用层映射到 HS.FHIRServer.Service 的入站 HTTP 管道。 在此标准 Web 架构中,客户端应用程序通过 HTTP/HTTPS 传输请求;系统会验证安全令牌、解析请求负载,并将操作委托给存储库实现,以支持创建、读取、更新和删除(CRUD)范式以及专门的搜索功能。

通过完全绕过标准 Web 服务器分发层,ObjectScript 例程可以实例化后端服务上下文,并直接与 InterSystems IRIS FHIR 存储库的核心引擎室进行交互。 这种方法使开发人员能够构建本机查询对象、管理排序参数、验证模式,并以最高性能和精确的控制来运行存储级搜索或直接读取记录。

  • GET:用于读取单个资源 (GET [base]/Patient/123) 或使用查询过滤器搜索集合(GET [base]/Patient?gender=male&birthdate=ge1980-01-01)。

  • POST:用于创建一个全新的资源(POST [base]/Patient)。

  • PUT:用于更新现有资源,或根据标识符(PUT [base]/Patient/123)对其进行更新或插入(upsert)。

  •  DELETE:用于删除或归档一条记录(DELETE [base]/Patient/123)。

 

当你在 GET 请求中加入查询参数时,就是在告诉服务器如何对数据进行切片和筛选。 然而,当你脱离浏览器或 Postman 时,IRIS 如何通过编程方式处理这些参数?与其完全依赖外部的 HTTP REST 层,不如使用 HS.FHIRServer.Service 直接在 IRIS 后端执行 FHIR 操作。

通过编程方式构建查询参数

在内部执行高级搜索时,规范地管理查询参数对于防止查询格式错误以及通过 JsonAdvSQL 执行引擎确保最佳性能至关重要。InterSystems 专门为此提供了 HS.FHIRServer.API.Data.QueryParameters。 根据数据来源的不同,您可以通过以下两种主要方法来构建并填充该对象:

· 方法 A:通过AddParameter() 手动构建: 如果您在应用程序逻辑中动态构建编程搜索条件(例如,根据内部业务规则、自定义 UI 中的用户选择或工作流状态构建查询),则应直接实例化 QueryParameters 类,并使用 AddParameter() 方法逐个添加过滤条件。 这种方法使您能够在查询到达 IRIS 存储层之前,对各个参数的名称、修饰符、前缀和值进行绝对控制。

· 方法 B:通过CreateFromQueryString() 从查询字符串进行解析:在处理原始 HTTP 请求时,您无需手动解析 URL 参数。InterSystems IRIS 在查询参数处理程序类中提供了一个原生实用方法——CreateFromQueryString()——可无缝地自动完成此转换。

通过编程方式对数据进行排序和链接

高级搜索需要通过显式参数配置,对结果排序和相关临床记录进行精确控制。

· 自动方式:在构建标准 FHIR 应用程序时,开发人员通常依赖传入的 REST URL。客户端可能会请求按最后更新日期降序排序的患者列表:GET [base]/Patient?gender=female&_sort=-_lastUpdated。 当您将此字符串传递给 HS.FHIRServer.API.Data.QueryParameters.CreateFromQueryString() 时,IRIS 会自动解析出 _sort 参数。

· 手动方式:如果您未使用 URL 查询字符串,或者希望在自定义交互类中拦截请求并强制采用特定的排序顺序(无论用户请求什么),则可以手动构建 .tSortKeys。 无需依赖字符串解析器,您可以在 ObjectScript 中显式构建排序数组。

· 正向链接(_include):它们沿着匹配资源向外的引用,提取相关实体(例如,搜索 MedicationRequest 资源并包含被引用的 Practitioner 或 Patient [MedicationRequest:patient])。

· 反向链接(_revinclude):它们从指向匹配资源的其他资源开始,向后追踪引用关系(例如,搜索“Patient”并提取所有引用该特定患者 ID 的“Observation”或“Encounter”记录 [Observation:patient])。

技术参考与实现代码示例

以下 ObjectScript 代码块演示了如何在 InterSystems IRIS 内部直接执行这些程序化工作流: 

   手动参数构建:

ClassMethod CreateParamsManually() As HS.FHIRServer.API.Data.QueryParameters
{
	Set params = ##class(HS.FHIRServer.API.Data.QueryParameters).%New()
    // Equivalent to filtering by ?gender=male
	Do params.AddParameter("gender", "male")
    // Equivalent to filtering by ?birthdate=ge1980-01-01
	Do params.AddParameter("birthdate", "ge1980-01-01")
    Quit params
}

从查询字符串中解析:

ClassMethod CreateParamsFromString() As HS.FHIRServer.API.Data.QueryParameters
{
	Set queryString = "gender=male&name=Smith"
    // Set tQueryString = "patient=123&date=ge2026-01-01&_include=Observation:patient&_count=50"
    // Automatically handles keys, values, prefixes (like 'ge'), and modifiers
	Set params = ##class(HS.FHIRServer.API.Data.QueryParameters).CreateFromQueryString(queryString)
	Return params
}

通过 FindSearchParam 验证模式元数据:为防止因无效查询条件或资源-属性不匹配导致的运行时错误,应在执行前检查活动模式元数据。tStrategy.Schema.FindSearchParam(pResourceType, pParamName) 充当安全检查机制。

ClassMethod ValidateSearchParameter(pStrategy As HS.FHIRServer.Storage.JsonStrategy, pResourceType As %String, pParamName As %String) As %Boolean
{
// Evaluates if the parameter is valid for the specified resource in the active FHIR version schema
	Set searchParam = pStrategy.Schema.FindSearchParam(pResourceType, pParamName)

    If $IsObject(searchParam) {
     	Write "Parameter '", pParamName, "' is valid for resource '", pResourceType, "'.", !
     	Quit 1
	}

    Write "Invalid search parameter for this resource schema.", !
	Quit 0
}

针对交互引擎的直接搜索执行:

ClassMethod ExecuteDirectSearch(pAppKey As %String) As %Status
{
	Set tSC = $$$OK
	Try {
     	// Instantiate the FHIR Service, which contains the strategy and interactions objects
     	Set fhirService = ##class(HS.FHIRServer.Service).EnsureInstance(pAppKey)
    	
        	// Access the underlying interactions engine through the strategy
     	Set tInteractions = fhirService.Strategy.GetInteractions()
    	
        	// Reusing our query parameter builder
     	Set tParams = ##class(HS.FHIRServer.API.Data.QueryParameters).CreateFromQueryString("gender=male")
    	
        	// Execute the Search method directly against the Interactions class
     	// Parameters: (ResourceType, Compartment, CompartmentId, QueryParameters, .SortKeys)
     	Set tSearchResult = tInteractions.Search("Patient", "", "", tParams, .tSortKeys)
    	
        	// Iterate through the search results object
     	Write "Total matches found: ", tSearchResult.Total, !
    	
        	// Loop through matching resource IDs or entries
     	While tSearchResult.Next(.tId, .tResourceJson, .tStatusCode) {
         	Write "Patient ID: ", tId, " | Details: ", tResourceJson.%ToJSON(), !
     	}
    	
    	} Catch tException {
     	Set tSC = tException.AsStatus()
     	Write "Error during search: ", $System.Status.GetErrorText(tSC), !
	}
	Quit tSC
}

通过 .Read() 直接检索资源:HS.FHIRServer.Storage.JsonAdvSQL.Interactions 上的 Read() 方法是核心编程功能,负责直接从存储库存储层获取特定单个 FHIR 资源的 JSON 数据,而无需运行搜索索引。

Set pResourceType = "Patient"
Set resourceId = "1"
// Retrieve the resource as a %DynamicObject directly using interactions.Read()
Set tInteractions = fhirService.Strategy.GetInteractions()
Set resourceString = tInteractions.Read(pResourceType, resourceId)
Write "Patient ID: ", resourceId, " | Resource Data retrieved successfully.", !

应避免的常见错误

· 绕过模式验证:在执行动态查询前跳过对 FindSearchParam() 的调用,这可能导致当属性与当前有效的 FHIR 资源模式版本不匹配时,引发未处理的运行时异常。

· 硬编码 REST 依赖关系:强制内部微服务或批处理引擎通过本地回环 HTTP 请求进行路由,而非在 ObjectScript 中直接调用 HS.FHIRServer.Service 和 GetInteractions()。

· 结果遍历不当:在遍历 HS.FHIRServer.Util.SearchResult 对象循环时,未能正确评估结果状态码,或使用了错误的属性查找。

 

常见问题解答 (FAQ)

问:是否可以在不发送 HTTP 服务器请求的情况下执行 FHIR 查询?

答:可以。通过实例化 HS.FHIRServer.Service 并提取交互引擎,ObjectScript 代码可以在内存中完全执行搜索和读取记录。

问:如何通过编程方式添加 _include 参数?

答:在 QueryParameters 实例上调用 AddParameter() 方法,将 _include 作为键,目标引用路径(例如 Observation:subject)作为值传入。

问:HS.FHIRServer.API.Data.QueryParameters 的用途是什么?

A: 它提供了一种结构化的机制,可在通过 JsonAdvSQL 存储层执行之前,以规范的方式构建、解析和封装查询条件、修饰符和前缀。

问:.Read() 与 .Search() 有何区别?

A: Read() 接受显式的资源类型和逻辑 ID,可立即以 %DynamicObject 形式检索单条记录;而 Search() 则对资源集合进行多参数过滤评估。

问:如何在没有 URL 字符串的情况下处理自定义排序?

A:您可以结合通过 tStrategy.Schema.FindSearchParam() 获取的模式定义,使用 .tSortKeys 手动定义排序数组。

问:为什么在程序化执行过程中需要进行模式验证?

A:这可确保搜索键、属性及修饰符映射符合当前有效的 FHIR 配置文件定义,从而防止执行错误。

实用建议 

在提取交互引擎之前,请务必使用 HS.FHIRServer.Service.EnsureInstance(pAppKey) 初始化运行时上下文。处理传入的文本映射时,请使用 CreateFromQueryString(),并通过 FindSearchParam 实现模式验证检查,以确保后端集成稳健且无误。

结论 

通过绕过标准的 REST 路由并以编程方式调用 InterSystems IRIS FHIR 交互引擎,开发人员可以以低开销的方式直接访问核心存储库。 利用手动查询参数进行搜索,并使用 Read() 方法进行定向资源检索,可提供高性能后端集成和自定义业务逻辑所需的最快速度、最高精度和最大的架构灵活性。