查找

文章
· 一月 31 阅读大约需 1 分钟

Gérer correctement l'heure système de mon conteneur IRIS

Dans un environnement conteneurisé, vous pouvez gérer l'heure de votre conteneur via la variable TZ ou via les répertoires /etc/timezone et /etc/localtime :

environment:
      - TZ=Europe/Paris
volumes:
    - "/etc/timezone:/etc/timezone:ro"
    - "/etc/localtime:/etc/localtime:ro"

Vous pouvez retrouver des exemples complets ici :

IRIS Community

IRISHealth_Community

IRIS production

IRISHealth production

讨论 (0)1
登录或注册以继续
问题
· 一月 31

How to use %ValidateObject with %Dynamic properties?

 I am creating a class to validate JSON body of requests. When I use the method %ValidateObject to check errors in the object, if I define some properties with %DynamicObject or %DynamicArray and use the Required parameter, this method does not work, it ignores validation, only works with properties %String, %Integer etc.

Class test.Example Extends %RegisteredObject
{

Property id As %Integer [ Required ];

Property name As %String [ Required ];

Property fieldOptions As %DynamicArray [ Required ];

Method %OnNew(id As %Integer, name As %String, fieldOptions As %DynamicArray) As %Status [ Private, ServerOnly = 1 ]
{
    Set ..id = id
    Set ..name = name
    Set ..fieldOptions = fieldOptions
}
// fieldOptions is ""
Set test = ##class(test.Example).%New(1, "name", "")

Set obj = test.%ValidateObject()

Set message = $System.Status.GetOneErrorText(obj, 1)

Write message

// Return is "OK"
2 Comments
讨论 (2)1
登录或注册以继续
文章
· 一月 31 阅读大约需 9 分钟

Implement a REST Dispatch Class with optional number of arguments to multiple endpoints

My main goal of this article was to prove the use of InterSystems IRIS for Health for REST FHIR interoperability between multiple applications. In this use case, some initiating application makes a REST call to IRIS for Health (which is merely a passthrough for REST calls) to retrieve FHIR data from an Oracle Health R4 FHIR repository. Ideally, it simplifies the syntax for calling the Oracle Health APIs. 

In this article, I will demonstrate a means for implementing a REST Dispatch Class in InterSystems IRIS, where multiple endpoints can have an optional number of arguments, and all endpoints reference a single class method. In this article, I am using IRIS for Health 2024.1.2, and making REST calls to a public FHIR sandbox for an Oracle Health Millennium Platform (aka Cerner Ignite FHIR), all with sample data (No real PII or PHI).

Note that I am doing everything Unauthenticated, as the public sandbox for Cerner Ignite FHIR does not require authentication, although it does require HTTPS.

Documentation Links To Oracle Health

Sample Oracle Health FHIR Data

https://docs.google.com/document/d/e/2PACX-1vQwyX3px4qi5t1O6_El6022zYt4y...

FHIR R4 APIs for Oracle Health Millennium Platform

https://docs.oracle.com/en/industries/health/millennium-platform-apis/mf...

Approach

The overall goal is to have multiple Url Routes in the <Routes> definition, with an optional number of parameters, and implement a single Class Method for all Url Routes. There are two approaches to this, and I will describe both, provide documentation links, and sample code. The two examples are 1) Specifying Parameters, or 2) Regular Expressions in the Route Map. The example code I use in the REST Dispatch class uses the first approach.

Specifying Parameters

https://docs.intersystems.com/iris20243/csp/docbook/DocBook.UI.Page.cls?...

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
 {
  <Routes>
   <Route Url="/Patient" Method="GET" Call="GetPatient" Cors="true"/> <!-- 0 parameters, returns an error --> 
   <Route Url="/Patient/:Param1" Method="GET" Call="GetPatient" Cors="true"/> <!-- 1 parameter --> 
   <Route Url="/Patient/:Param1/:Param2" Method="GET" Call="GetPatient" Cors="true"/> <!-- 2 parameters -->
   <Route Url="/Patient/:Param1/:Param2/:Param3" Method="GET" Call="GetPatient" Cors="true"/> <!-- 3 parameters -->
  </Routes>
 }

Regular Expressions in the Route Map

https://docs.intersystems.com/iris20243/csp/docbook/DocBook.UI.Page.cls?...

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
 {
  <Routes>
   <Route Url="/Patient" Method="GET" Call="GetPatient" Cors="true"/> <!-- 0 parameters, returns an error --> 
   <Route Url="/Patient/([^/]*)" Method="GET" Call="GetPatient" Cors="true"/> <!-- 1 parameter -->
   <Route Url="/Patient/([^/]*)/([^/]*)" Method="GET" Call="GetPatient" Cors="true"/> <!-- 2 parameters -->
   <Route Url="/Patient/([^/]*)/([^/]*)/([^/]*)" Method="GET" Call="GetPatient" Cors="true"/> <!-- 3 parameters -->
  </Routes>
 }

System Setup

I started with a Windows 11 Virtual Machine on my MacBookPro using VM Ware, with hostname = "vmirishealth-dlf". I enabled the IIS server to provide the Web Server needed for the IRIS installation.  I then installed IRIS for Health 2024.1.2, activated with a license key, then created a Namespace and corresponding database called CernerEMR. I then created a SSL/TLS Configuration called "ISC.Demo.Cerner.SSL".

I then created a REST Web Application called "/api/cerneremr" that implements a REST Dispatch Class called "ISC.Demo.REST.CernerServiceDispatch" that will be created below.

 ObjectScript Code

In my CernerEMR namespace, I created a class called ISC.Demo.REST.CernerServiceDispatch which extends %CSP.REST, added a Parameter defining portions of the URL for the Cerner APIs that could be used within the class, and defined the UrlMap with my REST Endpoints. Note I also defined Parameter HandleCorsRequest = 1; and Cors="true" for each route in my UrlMap.

Class ISC.Demo.REST.CernerServiceDispatch Extends %CSP.REST
{

Parameter HandleCorsRequest = 1;
Parameter FHIRURL = "/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
 {
  <Routes>
   <Route Url="/Patient" Method="GET" Call="GetPatient" Cors="true"/> <!-- 0 parameters, returns an error -->
   <Route Url="/Patient/:Param1" Method="GET" Call="GetPatient" Cors="true"/> <!-- 1 parameter -->
   <Route Url="/Patient/:Param1/:Param2" Method="GET" Call="GetPatient" Cors="true"/> <!-- 2 parameters -->
   <Route Url="/Patient/:Param1/:Param2/:Param3" Method="GET" Call="GetPatient" Cors="true"/> <!-- 3 parameters -->
  </Routes>
 }
}

I then added a ClassMethod called MakeHttpRequest that I could reuse for additional calls to Cerner for resources beyond the Patient (Practitioner, Locations, Appointments, etc which are not shown in this article, but would follow the same pattern used for the Patient resource). As part of this method, I added two headers required by the Oracle Health R4 APIs.

ClassMethod MakeHttpRequest() As %Net.HttpRequest
{
    // generate the HTTP REST request	
    set httprequest=##class(%Net.HttpRequest).%New()
    set httprequest.Https=1 ; to ensure HTTPS is used
    set httprequest.SSLConfiguration = "ISC.Demo.Cerner.SSL" ; required if using https
    set httprequest.Server="fhir-open.cerner.com"
    do httprequest.SetHeader("Accept","application/fhir+json")	
    do httprequest.SetHeader("Accept-Encoding","gzip,deflate")
    Quit httprequest
}

I then created a ClassMethod called GetPatient (as that is the method called for each REST Endpoint in my UrlMap). Note that I used an example from the documentation for using a variable number of arguments. This allowed me to use one single method for multiple endpoints, each with a variable number of arguments. The class method determines how many arguments have been passed in, and then formulates the correct parameter list that is suffixed on the REST URL.

I created the REST request, added my dynamic parameter list, sent that as a GET Request to the Oracle Health R4 FHIR Endpoint, and then forwarded the response payload from Oracle Health as JSON in my method's response.

Specifying a Variable Number of Arguments for a Method in InterSystems IRIS

https://docs.intersystems.com/iris20242/csp/docbook/DocBook.UI.Page.cls?...

ClassMethod GetPatient(param1... As %String) As %Status
{
    set httprequest = ..MakeHttpRequest()
    set tURL = $PARAMETER($THIS,"FHIRURL") 
    
    // dynamically build the parameter list based on unknown number of arguments
    set params = $GET(param1,0)
    // ensure we have a least 1 parameter, if not error
    if params > 0 {
        set paramList = "?"_$GET(param1(1))
        For i = 2 : 1 : params {
            set paramList = paramList _"&"_$GET(param1(i))
        }

        set status=httprequest.Get(tURL_"/Patient/"_paramList)
        if $$$ISERR(status) {
             do $system.OBJ.DisplayError()
             Quit $$$ERROR(status)
        } else {
             set response=httprequest.HttpResponse
        }

        set jsonObject = {}.%FromJSON(response.Data)
    } else {
        set jsonObject = {"errorMessage":"No Parameters passed in"}
    }
    do ##class(%JSON.Formatter).%New().Format(jsonObject)
    Quit $$$OK
}

To summarize with all of the code created, here is the full class:

Class ISC.Demo.REST.CernerServiceDispatch Extends %CSP.REST
{

Parameter HandleCorsRequest = 1;
Parameter FHIRURL = "/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
 <Routes>
  <Route Url="/Patient" Method="GET" Call="GetPatient" Cors="true"/>  <!-- 0 parameters which should error out -->
  <Route Url="/Patient/:Param1" Method="GET" Call="GetPatient" Cors="true"/> <!-- 1 parameter -->
  <Route Url="/Patient/:Param1/:Param2" Method="GET" Call="GetPatient" Cors="true"/> <!-- 2 parameters -->
  <Route Url="/Patient/:Param1/:Param2/:Param3" Method="GET" Call="GetPatient" Cors="true"/> <!-- 3 parameters -->
 </Routes>
}

ClassMethod MakeHttpRequest() As %Net.HttpRequest
{
    // generate the HTTP REST request	
    set httprequest=##class(%Net.HttpRequest).%New()
    set httprequest.Https=1
    set httprequest.SSLConfiguration = "ISC.Demo.Cerner.SSL" ; required if using https
    set httprequest.Server="fhir-open.cerner.com"
    do httprequest.SetHeader("Accept","application/fhir+json")	
    do httprequest.SetHeader("Accept-Encoding","gzip,deflate")
    Quit httprequest
}

ClassMethod GetPatient(param1... As %String) As %Status
 {
    set httprequest = ..MakeHttpRequest()
    set tURL = $PARAMETER($THIS,"FHIRURL") 
    
    // dynamically build the parameter list based on unknown number of arguments
    set params = $GET(param1,0)
    // ensure we have a least 1 parameter, if not error
    if params > 0 {
        set paramList = "?"_$GET(param1(1))
        For i = 2 : 1 : params {
            set paramList = paramList _"&"_$GET(param1(i))
        }

        set status=httprequest.Get(tURL_"/Patient/"_paramList)
        if $$$ISERR(status) {
             do $system.OBJ.DisplayError()
             Quit $$$ERROR(status)
        } else {
             set response=httprequest.HttpResponse
        }

        set jsonObject = {}.%FromJSON(response.Data)
    } else {
        set jsonObject = {"errorMessage":"No Parameters passed in"}
    }
    do ##class(%JSON.Formatter).%New().Format(jsonObject)
    Quit $$$OK
 }
}

Then an example REST call from my favorite REST Client (I used Insomnia 10.2.0) to retrieve Patient data (using 2 parameters) from Oracle Health R4 FHIR repository.

IRIS REST Call
GET http://vmirishealth-dlf/api/cerneremr/Patient/family=SMART/given=Nancy

which gets transformed into

Cerner REST Call
GET https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient?family=SMART&given=Nancy

This request returns 4 patients that satisfies the search request. The response below is truncated to show only the total number of resources, and the id of the first patient, which is 12724066

{
	"resourceType": "Bundle",
	"id": "6227ca9f-30da-4e49-80c1-902d34b420a7",
	"type": "searchset",
	"total": 4,
	"link": [
		{
			"relation": "self",
			"url": "https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient?family=SMART&given=Nancy"
		}
	],
	"entry": [
		{
			"fullUrl": "https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient/12724066",

This is an example REST call that asks for Patient by id (12724066), using 1 parameter.

IRIS REST Call
GET http://vmirishealth-dlf/api/cerneremr/Patient/_id=12724066

which gets transformed into

Cerner REST Call
GET https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient?_id=12724066

and the truncated response that shows 1 resource returned, and the name of the patient.

{
	"resourceType": "Bundle",
	"id": "916f95b6-5f95-4722-9425-3b5019f6c45c",
	"type": "searchset",
	"total": 1,
	"link": [
		{
			"relation": "self",
			"url": "https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient?_id=12724066"
		}
	],
	"entry": [
		{
			"fullUrl": "https://fhir-open.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d/Patient/12724066",
			"resource": {
				"resourceType": "Patient",
				"id": "12724066",
				"meta": {
					"versionId": "1465",
					"lastUpdated": "2024-10-07T05:02:43.000Z"
				},
				"text": {
					"status": "extensions",
					"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Patient</b></p><p><b>Name</b>: SMARTS II, NANCYS II</p><p><b>Status</b>: Active</p><p><b>DOB</b>: Sep 15, 1990</p><p><b>Birth Sex</b>: Female</p><p><b>Administrative Gender</b>: Female</p><p><b>Marital Status</b>: Divorced</p></div>"

Hopefully this technique comes in handy.

TBD - I plan to record a YouTube video and add the code to https://openexchange.intersystems.com.

讨论 (0)1
登录或注册以继续
问题
· 一月 31

How to troubleshoot VSCode extension? Package not appearing in workspace.

I have VS Code with extensions connected to IRIS for Health. One top-level ObjectScript package is not displayed in the workspace for this namespace. This package exists in the namespace and is visible in SMP. If I create a new class with a different top-level package name (package that didn't previously exist) it will immediately appear in the workspace.

Is there any debug logging I can enable to look for errors or do any other troubleshooting?

Forgot to mention: the missing package is custom, not a system package.

5 Comments
讨论 (5)3
登录或注册以继续
问题
· 一月 31

Migrate to nginx server

I have an Iris Intersystems instance that works with Apache server  on Windows 11 machine. Are there any clear and simple instruction or documentation  that explain how to migrate from Apache server to Nginx server?

2 Comments
讨论 (2)4
登录或注册以继续