検索

文章
· 十二月 8, 2023 阅读大约需 2 分钟

Business Service to Query Internal IRIS database

Scenario

IRIS has the likes of SQL inbound adapters for use with SQL gateways such as EnsLib.SQL.InboundAdapter to repeatedly query SQL Gateway connections. A scenario appeared as that we wanted to query an Internal database for some data but did not see an out of the box service for this. 

Desired Approach

Have a Generic service that can poll internal SQL to work with downstream components.

How

What was not clear was "How do I send a result set downstream". It was not very clear as a resultset itself is not a peristent class and the object cannot be "Swizzled" an error like so 

 <METHOD DOES NOT EXIST>zNewRequestMessage+4 ^Ens.MessageHeader.1 *%GetSwizzleObject,%sqlcq.SRFT.cls535 -- logged as '-'
number - @''

The solution was using the object 

EnsLib.SQL.Snapshot

This can then be used as a business operation to send a resultset downstream in using the function Import from resultset

set result=##class(EnsLib.SQL.Snapshot).%New()
// Some SQL query here resulting in resultset where rset is the resultset object
set tSC=result.ImportFromResultSet(rset)

You can then send this on to another operation 

set tSC=..SendRequestAsync(..ForwardComponentName,result,0)  Quit:$$$ISERR(tSC)

 

Note in the code uploaded to open exchange available here via github . The example is you can open it up and query it. The below is the classmethod that is used to put into a html. This differs from released example slightly as is taken from a live implementation. 

ClassMethod GetDataTable(pRequest As EnsLib.SQL.Snapshot, html As %String) As %String
{
  //first html obj can be if the styling needs passed
  if $ISOBJECT(html){set html=""}
  //loop get column titles 
  set ColumnIteration=1
  set ColumnCount=pRequest.%ResultColumnCountGet()
  
  set html=html_" <table class=""tg"">"
  set html= html_ " " _"<tr>"
  set meta=pRequest.%GetMetadata() //this is like raw text of the result using it to get the column titles out
  if ColumnCount>0{
    while ColumnIteration<=ColumnCount{
      
      set html= html_ " <th>"_  meta.columns.GetAt(ColumnIteration).colName _" </th>"
      set ColumnIteration=ColumnIteration+1
    }

  }
  set html= html_ " " _"</tr>"
  //not get the data from each row. In html need a <tr> and a td. 
  set coldataiteration=1
  While pRequest.%Next() {
    set html= html_ " <tr>"
    while coldataiteration <=ColumnCount{
      set html= html_ " <td> "_pRequest.%GetData(coldataiteration) _" </td>"
      set coldataiteration=coldataiteration+1
    }
    
    set html= html_ " </tr>"
    set coldataiteration=1
  }
  set html= html_ " " _"</table>"
  $$$TRACE(html)
  return html
}

Sparkei/Internal-SQL-Service: Intersystems service that can be used to query an internal SQL table to send a snapshot downstream (github.com)
 

讨论 (0)1
登录或注册以继续
文章
· 十二月 4, 2023 阅读大约需 10 分钟

通用RESTful 业务服务和业务操作

1. 通用RESTful业务服务和业务操作


InterSystems IRIS 提供了一组通用的RESTful 业务服务和业务操作类,用户无需开发自定义的业务服务和业务操作类,就可以直接向外提供RESTful服务和调用外部的RESTful API。

BS EnsLib.REST.GenericService 通用REST业务服务
BS EnsLib.REST.SAMLGenericService 检查SAML令牌的签名和时间戳的REST业务服务
BO EnsLib.REST.GenericOperation 通用REST业务操作
BO EnsLib.REST.GenericOperationInProc 用于透传模式的通用REST业务操作

 

2. 通用RESTful 消息

 

通用的RESTful 业务服务和业务操作类使用一个通用的RESTful消息类 - EnsLib.REST.GenericMessage,它是EnsLib.HTTP.GenericMessage的子类,二者数据结构都是

HTTPHeaders 记录http头的数组
Stream 记录http体的数据流
Type 数据流类型,例如是字符流还是二进制流。自动赋值,无需设置
Attributes 记录属性的数组
OriginalFilename 无需使用
OutputFolder 无需使用
OutputFilename 无需使用

因此EnsLib.REST.GenericMessage和EnsLib.HTTP.GenericMessage都可以被通用RESTful业务操作和业务服务所使用。

 

3. 通用RESTful 业务操作

使用通用的RESTful业务操作,可以连接到任何第三方的RESTful服务器,调用其RESTful API。

3.1 向production中加入通用RESTful业务操作

增加通用RESTful业务操作,只需要在Production配置页面的操作中添加EnsLib.REST.GenericOperation。

建议加入Production时,给业务操作起一个名字,用于代表具体的业务,例如是连接到LIS的RESTful 服务,可以命名为RESTtoLIS(可以考虑的命名规则 - 接口方式+业务系统)。如果未命名,默认会使用类名作为业务操作名。

3.2 配置通用RESTful业务操作

主要的设置项是以下3个:

1. HTTP服务器:目标RESTful服务器的服务器名或IP地址

2. HTTP端口:目标RESTful服务器提供RESTful API的端口号

3. URL:RESTful API的服务端点

启用该业务操作后,既可以访问外部RESTful API了。

注意,这里URL可以不填写,而由HTTP header动态指定。

3.3 测试通用RESTful业务操作

启用后,加入的通用的RESTful业务操作即可测试了。因为EnsLib.HTTP.GenericMessage的REST消息体是一个流类型的属性,为了测试时方便输入这个数据,我们增加一个业务流程。

1. 创建一个新的业务流程,设置其请求消息为Ens.StringRequest,用于测试时传入REST body数据。并为其上下文增加一个名为DataBody、类型为%Stream.GlobalCharacter(可持久化的字符流类型)的属性:

2. 在业务流程中增加一个代码流程(<code>),将请求消息的字符串数据写入上下文的DataBody字符流:

Do context.DataBody.Write(request.StringValue)

 注意行首加空格。

 

3. 然后在业务流程中再加入一个调用流程(<call>),调用上面已经加入production的业务操作,例如RESTtoLIS,并设置请求和响应消息为EnsLib.REST.GenericMessage或EnsLib.HTTP.GenericMessage。

4. 配置RESTtoLIS业务操作的请求消息(Request)

可以直接点击构建请求消息(Request Builder)按钮,使用图形化拖拽建立请求消息:

4.1 将左边上下文context里的DataBody拖拽到callrequest的Stream属性上;

4.2 对callrequest的HTTPHeaders赋值,它是一个元素类型为字符串的数组,代表HTTP请求的头。以下3个HTTP头是必须要填写的:

HTTP头属性说明 下标
HTTP方法 "httprequest" 例如"POST"
HTTP消息体的内容类型 "content-type" 例如"application/json"
客户端希望接收的内容类型 "Accept"  例如"*/*"

这3个数组元素赋值,可以通过在添加操作下拉列表中设置(Set)进行赋值。

4.3 (此步可选)如果在3.2中没有配置URL,则可以在这里增加对HTTPHeaders里URL的设置。例如需要动态确定URL,就可以在这里进行配置。如下:

注意,如果这里设置了“URL”,它会覆盖在BO设置中的URL。

4.4 (此步可选)如果有URL参数需要配置,例如/fhir/r4/MedicationRequest?Patient=0a8eebfd-a352-522e-89f0-1d4a13abdebc&_elements=medicationReference,这里需要设置2个URL参数:Patient和_elements,可以用HTTPHeaders的IParams进行设置。

设置方法是:

先确定有多少个参数,将数量放在IParams里,例如2个,所以设置IParams为2;

之后为每个参数设置IParams_i,这里i是参数序号,例如设置IParams_1为“Patient=0a8eebfd-a352-522e-89f0-1d4a13abdebc”;

以此类推。

 

5. 将业务流程加入Production,并测试

确保Production的设置是允许调试。在Production配置页面中选中这个业务流程,在右侧的操作标签页中选择测试按钮,并在弹出的测试消息页面里填入测试用的数据,并点击调用测试服务

然后可以检查测试的消息处理流程,并确认REST消息体和HTTP消息头被正确地传递到目标REST API

 

 

4. 通用RESTful 业务服务

使用通用的RESTful业务服务,可以向外发布能处理任何RESTful API调用请求的RESTful服务端。

4.1 将通用RESTful业务服务加入Production

在Production配置页面,点击服务后面的加号。弹出的向导页面,服务类选择EnsLib.REST.GenericService;输入服务名,建议写一个能代表组件功能的名字,例如向HIS系统开放的REST服务,可以起名RESTforHIS;选中立即启用。

RESTful通用业务服务可以通过2种方式向外提供RESTful API服务:第一种通过Web服务器向外提供服务,第二种使用IRIS服务器的特定TCP端口向外提供服务。第二种方式不依赖于独立的Web服务器,但推荐使用Web服务器,从而得到更好的性能和安全性。

这里我们使用Web服务器提供REST服务,因此在业务服务的端口配置中,保持空白。在接受消息的目标名称中,选择接收RESTful API请求的业务流程或业务操作,这里我们测试使用一个空的业务流程。点击应用激活这些设置。

4.2 建立一个向外提供RESTful API的Web应用

向外发布RESTful服务,不仅涉及到服务发布的URL,还涉及到安全。我们通过创建一个专用的Web应用来进行管理和控制。

在IRIS系统管理门户>系统管理>安全>应用程序>Web应用程序 中,点击新建Web应用程序按钮,新建一个Web应用程序,并做以下配置:

1. 名称,填写一个计划发布的服务端点,例如/IRISRESTServer。注意前面的/

2. NameSpace,选择Production所在的命名空间

3. 选中启用 REST,并设置分派类EnsLib.REST.GenericService

4. 根据安全需要,配置安全设置部分。这里方便测试起见,允许的身份验证方法选择了未验证(无需验证)。如果是生产环境,或者您在做性能压力测试,都应该选择密码Kerberos安全的身份验证方式!

注意,请保证同一个命名空间下,仅有一个分派类为EnsLib.REST.GenericService的REST类型的Web应用。

 

4.3 测试RESTful业务服务

现在就可以测试这个RESTful业务服务了。这个RESTful服务可以响应任何REST API的请求,如何响应则是后续业务流程/业务操作的事。

它的完整的RESTful URL是:[Web服务器地址]:[Web服务器端口]/[Web应用的名称]/[通用REST服务在production中的配置名]/[API名称和参数],例如我在IRIS本机的私有Apache的52773端口上访问上面创建的REST通用业务服务,调用PlaceLabOrder的API (注意,这里我们并没有实现过PlaceLabOrder这个API,但我们依然可以响应,而不会报404错误),那么完整的REST 调用地址是:

127.0.0.1:52773/IRISRESTServer/RESTforHIS/PlaceLabOrder

打开POSTMAN,用POST方法,发起上面REST API的调用:

 在IRIS里会得到类似这样的消息追踪结果,如果你没有实现过处理REST API请求的业务流程,会得到一个500错,但依然可以查看IRIS产生的EnsLib.HTTP.GenericMessage消息内容:

这个通用RESTful业务服务会把REST请求转换为EnsLib.HTTP.GenericMessage消息,向目标业务操作/业务流程发送。因此,通过解析它的消息内容,就知道REST API请求的全部信息:

1. Stream里是POST的数据

2. HTTPHeaders 的下标"HttpRequest"是HTTP的方法

3. HTTPHeaders 的下标"URL"是完整的API路径,包括了服务端点(在"CSPApplication"下标下)、REST业务服务名称(在"EnsConfigName"下标下)和API

后续业务流程可以通过这些数据对REST API请求进行响应。

4.4 使用业务流程对REST API调用进行路由

有了通用RESTful业务服务生成的EnsLib.HTTP.GenericMessage消息,我们就可以使用消息路由规则或业务流程对REST API请求进行路由。这里我使用业务流程方法对REST API请求进行路由演示。

构建一个新的业务流程,请求消息和响应消息都是EnsLib.REST.GenericMessage或EnsLib.HTTP.GenericMessage,同时为context增加一个名为ReturnMsg的字符串类型的属性,并设置它默认值为:"{""Code"":-100,""Msg"":""未实现的API""}"。

在业务流程里增加一个<switch>流程,然后在<switch>下增加2个条件分支,分别为:

名称:下达检验医嘱,条件:判断是否http头的URL为PlaceLabOrder,且http头的HttpRequest为POST:

(request.HTTPHeaders.GetAt("URL")="/IRISRESTServer/RESTforHIS/PlaceLabOrder") && (request.HTTPHeaders.GetAt("HttpRequest")="POST")

名称:查询检验项目,条件:判断是否http头的URL为GetLabItems,且http头的HttpRequest为GET:

(request.HTTPHeaders.GetAt("URL")="/IRISRESTServer/RESTforHIS/GetLabItems") && (request.HTTPHeaders.GetAt("HttpRequest")="GET")

在两个分支里,分别增加<code>, 产生返回的REST消息内容:

 Set context.ReturnMsg="{""Code"":200,""Msg"":""检验医嘱下达成功""}"
 Set context.ReturnMsg="{""Code"":200,""Msg"":""查询检验项目成功""}"

最后在<switch>后增加一个<code>,构建响应消息:

 // 初始化响应消息
 set response = ##class(EnsLib.REST.GenericMessage).%New()
 // 初始化响应消息的流数据
 Set response.Stream = ##class(%Stream.GlobalCharacter).%New()
 // 将REST返回数据写入流
 Do response.Stream.Write(context.ReturnMsg)

编译这个业务流程,并将其加入Production。

之后修改通用RESTful业务服务的设置,将接收消息的目标名称改为这个新建的业务流程。

现在再通过POSTMAN测试一下各种API,并查看返回REST响应:

在真实项目中,根据实际情况,将上面<switch>流程分支的<code>替换为API响应业务流程或业务操作即可。

 

总结:使用通用RESTful业务操作和业务服务,无需创建自定义的RESTful 业务组件类,就可以调用外部RESTful API和向外提供RESTful API服务,降低开发和实施成本,实现低代码开发。

 

后记:关于EnsLib.REST.GenericService对CORS(跨域资源共享)的支持

CORS是一种基于 HTTP 头的机制,通过允许服务器标示除了它自己以外的其它origin(域、协议和端口)等信息,让浏览器可以访问加载这些资源。
所以要让EnsLib.REST.GenericService支持CORS,需要让它的响应消息增加对于CORS支持的HTTP头的信息,这里不详细介绍这些头含义了,大家可以去W3C的网站或者搜索引擎查询具体定义,最简单可以使用以下代码替代上面4.4中的初始化响应消息代码:

  // 设置HTTP响应的头信息
  set tHttpRes=##class(%Net.HttpResponse).%New()
  set tHttpRes.Headers("Access-Control-Allow-Origin")="*"
  set tHttpRes.Headers("Access-Control-Allow-Headers")="*"
  set tHttpRes.Headers("Access-Control-Allow-Methods")="*"
  // 初始化响应消息
  set response = ##class(EnsLib.REST.GenericMessage).%New(,,tHttpRes)

 

关于Cookies:
很多REST API需要事先登陆,获取会话信息并保存到Cookies中,从而作为后续API调用的认证信息。

这种情况下,需要开启Cookies。开启方法是打开REST业务操作组件的配置项“使用Cookie”,见下图。

在开启后,上次API调用返回的消息中的Cookies信息会被保存到业务组件实例中,并在下次API调用时自动加到HTTP头中。

注意,这是针对于同一个REST业务操作组件的。Cookies并不会跨不同的REST业务操作组件共享!


关于返回消息的乱码:

如果你看到返回的REST消息是中文乱码,需要取消选中“阅读原始模式”,见下图。它默认是选中的,意思是不管HTTP头里声明的Charset是什么,它都不会进行转码,因此很适合透传。但如果取消选中该设置,IRIS会基于HTTP头的Charset进行转码,转为IRIS的内码Unicode,从而在消息追踪页面显示正确的中文。

关于HTTPS:

如果IRIS的REST客户端使用HTTPS访问REST服务器端,需要在IRIS实例上配置SSL客户端:

在IRIS系统管理门户>系统管理>安全>SSL/TLS配置中,点击“新建配置”:

输入“配置名称”;

然后“类型”选中“客户端”;

并在“此客户端的凭据” 选择证书文件和密钥文件。如果你手头上没有,可以用openssl生成一对。

保存后,可以测试一下。

然后在BO的配置页面的“Connection Settings”>SSLConfig中选中上一步创建的SSL客户端名称;同时保证HTTPPort里填写正确的端口号,默认HTTPS的端口号是443:

讨论 (0)1
登录或注册以继续
问题
· 十一月 20, 2023

Error on FHIR resource publish through Process to FHIR repository

I have received 2 errors while publishing Patient data to repository. Message viewer displays like below and the Application log found  bold content.

Could you please help me on this to resolve the errors.

An error occurred with the web application.
It has been logged to system error log (System Operation>System Logs>Application Error Log).

"<METHOD DOES NOT EXIST>OnPage+42^EnsPortal.MessageContents.1 *%Id,HS.FHIRServer.API.Data.Request : CSP Error"

Business Operation Event logs displays "ERROR <Ens>ErrRequestNotHandled: Request message '3@HS.FHIRServer.API.Data.Request' not handled"

Please suggest what is the issue here ..

Thanks,

6 Comments
讨论 (6)3
登录或注册以继续
文章
· 十一月 19, 2023 阅读大约需 1 分钟

NativeAPI for Java from WebTerminal

Based on the successful solution for my 2nd contribution to the Contest 
I used an adapted version for this package. And have some findings I'd like to share.

Multiple communication steps over CPIPE may take time.
You won't recognize it on a fast machine. But a slower box with
Windows + Docker Desktop + your browser (and more) is neither
"Speedy Gonzales" nor a "Road Runner". 🙂

First observation you launch your OS command and see NO result
On the console, you just sit there and expect a reply.
Establishing the Connection to IRIS is a typical case.
Jour redirected Output is just empty.  

This happens every now and then since between submission of
the user input, execution, and filling of the redirection file is a delay.
Reading of the output file immediately after command submission
doesn't make sense.

So I had to add a delay before checking the result.
As the delay was not sufficient in some cases also a RePaint was added,

I also observed a similar effect also with my command pipe.
To avoid missing content it sometimes required double submission.
I didn't find a real solution, just a workaround.
It mostly happened in my private box.
The OpenDempServer was always fast enough.

Suggestions on how to trace and solve this are welcome.

1 Comment
讨论 (1)1
登录或注册以继续
文章
· 十一月 16, 2023 阅读大约需 5 分钟

Accessing the IRIS Terminal: A Comprehensive Guide for Visual Studio Code Users

Introduction

Since InterSystems has recently announced the discontinuation of support for InterSystems Studio starting from version 2023.2 in favor of exclusive development of extensions for the Visual Studio Code (VSC) IDE, believing that the latter offers a superior experience compared to Studio, many of us developers have switched or are beginning to use VSC. Many may have wondered how to open the Terminal to perform operations, as VSC does not have an Output panel like Studio did, nor an integrated feature to open the IRIS terminal, except by downloading the plugins developed by InterSystems.

Summary

  • Introduction 
  • Solutions
    • For Users with at least IRIS 2020.1 or IRIS IRIS 2021.1.2  – Use Web Terminal
    • For Users with at least IRIS 2023.2 – Use WebSocket Terminal
    • For Users with Docker-based IRIS
    • For users with IRIS Versions Prior to 2023.2 working on their local machine
    • For Users Coding on IRIS based on a remote server using an SSH connection

Solutions

There are various ways to open the Terminal in VSC, depending on the specific configuration you are using, I've summarized here the best solutions for any situation:

For Users with at least IRIS 2020.1.1 or IRIS 2021.1.2 – Use Web Terminal

Users that have at least IRIS 2020.1.1 or IRIS 2021.1.2 and that are allowed to install external extensions (somebody may be not due to his company policy about third party applications), might find useful the Web Terminal extension for VSC. For who doesn’t know, the Web Terminal is a web-based terminal for InterSystems products built with ObjectScript (e.g., IRIS, Caché, Ensemble, HealthShare, TrakCare) that allows to use a more advanced version of the Terminal inside the browser (here the project page). This VSC extension enables to launch a web-based terminal directly from VSC, with a simple click.

In order to open the Web Terminal, click on: InterSystems Tools  > select a namespace > click on one of the following icons (, ) to open Web Terminal on VSC terminal panel or on browser (press Alt to change the default icon):

 

 

For Users with at least IRIS 2023.2 – Use WebSocket Terminal

Users with at least IRIS 2023.2 can take advantage of the new "WebSocket Terminal" feature included in the latest version of the VSC extensions and they don’t need for additional workarounds.

In order to open the WebSocket Terminal, click on: InterSystems Tools > select a namespace > click on the icon next to the Web Terminal one.

Edit: For further information, check the interesting article @Brett Saviano wrote about it!

How to run ObjectScript commands in the VS Code integrated terminal

For Users with Docker-based IRIS

Those working with IRIS environments within Docker and using VSC can start a terminal session directly within the Docker environment.  

Click on the Docker voice in the Status Bar, and then choose Open Terminal in Docker.

I would like to thank @Evgeny Shvarov for the picture and the explanation about this point.

 

For users with IRIS Versions Prior to 2023.2 working on their local machine

For users that work with a version of IRIS that runs on their local machine, it is possible to set up a dedicated IRIS terminal within VSC:

    1. Open the settings.json file. You can find it in several ways, for example by clicking on View > Command Palette > type: “settings” > Open User Settings (JSON)
    2. Add the following code under "terminal.integrated.profiles.windows":
"terminal.integrated.profiles.windows":{

    "IRIS Terminal": {
    
        "path": [
    
            "C:\\InterSystems\\IRISHealth\\bin\\irissession.exe"
        ],
    
        "args": ["IRISHEALTH"],
    
        "icon": "terminal-cmd"
    } 

}

Note: Insert the right path of your irissession.exe.

c. To open the Terminal from VSC navigate to: Terminal > New Terminal > Launch Profile… > IRIS Terminal.

d. An 'IRIS Terminal' voice should now be available in the Terminal menu:

 

For Users Coding on IRIS based on a remote server using an SSH connection 

For those who work on a version of IRIS based on a remote server (e.g., a company server) accessible via SSH connection (e.g., using PuTTY) it is possible to use the Remote - SSH VSC extension to connect VSC directly to the server. In order to do so:

    1. Install the Remote - SSH: Editing Configuration Files extension on VSC;
    2. Click on the “Remote Explorer icon  in the sidebar;
    3. Select “Open SSH Config File

  

and open the configuration file with the path: C:\Users\<username>\.ssh\config

    1. Insert the following code into the configuration file: 
Host my-putty-connection

    HostName < IP address or server name >

    User < username >

    IdentityFile < private key path on your local machine >

    Port < port > 

The IP Address and Port correspond to the Host Name and Port specified in PuTTY, the Username is the user credential used to access the remote server and the IdentityFile is the file path to your PuTTY private key.

Note:  The original format of the private key generated by PuTTY (.ppk) cannot be read by VSC. To establish a connection between VSC and the remote server via PuTTY, you must duplicate the original private key and convert the new version into the .pem format. In order to do the conversion:

  1. Launch PuTTYgen application
  2. Under File menu, click Load private key
  3. Select your private key in .ppk format, then choose Open
  4. Under the Conversions menu, click Export OpenSSH Key (force new file format).
  5. Set a new name with the .pem extension and click the Save button.
  6. Link the path of this new .pem file to the IdentifyFile parameter in VSC
    1. Save the file. After a few seconds the new connection should appear in the Remote Explorer panel;
    2. Click "Connect in New Window..." to open the SSH connection in a new VSC window:
  7.  Select the operating system of your remote machine (only at the first access)
  8. In the new window, navigate to: Terminal New Terminal (or use the shortcuts Ctrl + ò or Ctrl + Shift + ò).
  9. You're now connected to the remote machine and can use its IRIS Terminal within VSC.

Note: This operation only works if you have initiated your remote connection via PuTTY previously and does not function when PuTTY is closed or when you are not connected to the remote server. This operation does not launch PuTTY, it only allows VSC to connect to the tunnel established by PuTTY.

To initiate a PuTTY connection through VSC, you can utilize a batch file (on Windows). The provided connect_remote.bat file employs the Plink command, which is included with PuTTY, to start a session:

@echo off

set SESSION="<your saved session name>"

plink -load %SESSION%

To start the session, simply type .\connect_remote.bat in VSC terminal to open the remote connection and insert your credentials.

Note: This latter method provide you the access to a Terminal version that supports all VSC shortcuts! Welcome back Ctrl+V, goodbye Shift+Insert 🎉

10 Comments
讨论 (10)6
登录或注册以继续