I have many of examples of handling this using JDBC connection to Microsoft SQL Server. Either you can build an all-encompassing Custom Business Operation or use the EnsLib.SQL.Operation.ProcOperation. When inserting data into a table depending on how busy your Process is, I would suggest using Stored Procedures to insert the data.

Using a Dynamic SQL statement can cause some overhead because the Query is not Cached, so you are building it on your machine, then having to build it again when it is sent to the external connection. With a Patient Demographic (ADT) HL7 interface that extra overhead could cause everything to slow down.

The Begining of my Custom Business Operation looks like this...

Include (EnsSQLTypes, %occODBC) 

Class osuwmc.Visit.VisitDBWriteOperation Extends Ens.BusinessOperation [ ClassType = "", ProcedureBlock ] 
{ 

Parameter ADAPTER = "EnsLib.SQL.OutboundAdapter"; 

Parameter INVOCATION = "Queue"; 

Property InitDSN As %String; 

Method OnInit() As %Status 
{ 
Set ..InitDSN = ..Adapter.DSN 
//Set ..Adapter.ConnectAttrs = "QueryTimeout:45" ; try this too just in case... 
Kill $$$EnsRuntimeAppData(..%ConfigName) 

Quit $$$OK 
} 

Then for each stored procedure I call I have a different Method that uses its own Data Message Class Structure, the Message Map takes the incoming Data Message Class, and it knows which Method to call.

Method InsertCaseScheduleSp(pRequest As osuwmc.Visit.DataStructures.InsertCaseSchedule, Output pResponse As Ens.Response) As %Status 
{ 
set SPQuery = "{ ?= call dbo.usp_Interfaces_Insert_CaseSchedule_Ens(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}" 
set par = 15 
set par(1) = pRequest.CSN 
set par(2) = pRequest.MRN 
set par(3) = pRequest.CaseNum 
set par(4) = pRequest.SchedDate 
set par(5) = pRequest.OrderNum 
set par(6) = pRequest.LocationDescription 
set par(7) = pRequest.Duration 
set par(8) = pRequest.DurationUnits 
set par(9) = pRequest.CreationDate 
set par(10) = pRequest.CreationUser 
set par(11) = pRequest.ArrivalUser 
set par(12) = pRequest.EditingUser 
set par(13) = pRequest.NoShowUser 
set par(14) = pRequest.CancelUser 
set par(15) = pRequest.Status 

set tSC = ..Adapter.ExecuteProcedureParmArray(.caseschedinsert,.outputs,SPQuery,"oiiiiiiiiiiiiiii",.par) 
kill caseschedinsert 
kill SPQuery 
kill par 
Quit tSC 
}

Data MessageMap 
{ 
<MapItems> 
<MapItem MessageType="osuwmc.Visit.DataStructures.InsertCaseSchedule"> 
<Method>InsertCaseScheduleSp</Method> 
</MapItem> 
</MapItems> 
}

We send our alerts through the SMTP server for Microsoft Exchange, but have not been required to use SSL as of yet.

If I don't see the Global associated with a Class, it doesn't seem to be getting cleaned up within the Daily Purge. So how do we clean these up in some cases?

If I search in VSCode using the global name, nothing is returned. So, either the Class file was recompiled to a new global, or no longer in the system.

These globals were created as part of %Persistent Data Classes that did not use Ens.Request or Ens.Response.

  1. never thought about reviewing messages.log, or the journalling log to see if there is an error, but I will double check.
  2. The Business Rule in question has always been a part of the database that is part of the mirror.

SendRequestAsync did not work... <METHOD DOES NOT EXIST>  OnTask+12^OSU.Workday.TerminationsTask.1 SendRequestAsync,Ens.BusinessService
 

Do you have to create a Property of EnsLib.SQL.Snapshot, or can you just extend your data class to EnsLib.SQL.Snapshot?

Class ResponseMessage Extends Ens.Response
{

 Property snapShotProp As EnsLib.SQL.Snapshot;

Or

Class ResponseMessage Extends EnsLib.SQL.Snapshot
{

So, if we are just extending EnsLib.SQL.Snapshot as a property in a new Response class, is it still not linked to Ens.AppData?

It has been disabled in our environment, found that it could not handle the number of Objects we had in a Large Namespace.

If you have a Business Rule that identifies a Message but does a Return instead of a DTL could it be creating a message?

Would I have to define a OnTask within the Business Service, or is that built in?

@Robert Hurst 

I am finding that when I compile class files that Extends Common.JDBC.MakeRequestClass at least in 2025.1 it is not generating the necessary Message Class correctly. Have you experienced that?

And I had thought I had set a record with the number of lines I had in a process.... 

Updated all the Child Data Structures to be %SerialObjects instead of %RegisteredObjects, but that did not make a difference. I am still not seeing anything within the Trace Viewer when the Response is sent back to the Process.

I was able to figure it out, and get it to work..

Class osuwmc.DataLookup.REST.TableLookup Extends osuwmc.DataLookup.REST.Base
{

Parameter Version = "1.0.0";

Parameter HandleCorsRequests = 0;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes> 
    <!-- Server Info -->
    <Route Url="/" Method="GET" Call="GetInfo" />
    <Route Url="/EpicDepartment" Method="GET" Call="GetAllEpicDepartments" />
    <Route Url="/EpicDepartment/:departmentID" Method="GET" Call="GetEpicDepartment"/>
    </Routes>
}

ClassMethod GetInfo() As %Status
{
    SET version = ..#Version
    SET info = {
      "version": (version)
    }
    RETURN ..%ProcessResult($$$OK, info)
}

ClassMethod GetAllEpicDepartments() As %Status
{
    SET tSC = $$$OK
    set %response.ContentType = ..#CONTENTTYPEJSON
    set rset = ##class(osuwmc.Epic.Clarity.DepartmentMaster).ExtentFunc()
    write "["
    if rset.%Next(){
      set department = ##class(osuwmc.Epic.Clarity.DepartmentMaster).%OpenId(rset.ID1)
      do department.%JSONExport()
    }
    while rset.%Next(){
      write ","
      set department = ##class(osuwmc.Epic.Clarity.DepartmentMaster).%OpenId(rset.ID1)
      do department.%JSONExport()
    }
    write "]"
    quit tSC
}

ClassMethod GetEpicDepartment(departmentID As %String) As %Status
{
  #dim tSC as %Status = $$$OK
  #dim e As %Exception.AbstractException
  #dim id as %Integer

  set %response.ContentType = ..#CONTENTTYPEJSON
  &sql(SELECT ID1 INTO :id FROM osuwmc_Epic_Clarity.DepartmentMaster WHERE ID = :departmentID)
  IF SQLCODE<0 {WRITE "SQLCODE error ",SQLCODE," ",%msg  QUIT}
  ELSEIF SQLCODE=100 {WRITE "Query returns no results"  QUIT}
  set department = ##class(osuwmc.Epic.Clarity.DepartmentMaster).%OpenId(id)
  Do department.%JSONExport()
  QUIT tSC
}

ClassMethod SwaggerSpec() As %Status
{
  Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger)
  Do swagger.info.%Remove("x-ISC_Namespace")
  Set swagger.basePath = "/api/mgmnt/v1/TESTCLIN/spec/TableLookup"
  Set swagger.info.title = "REST API to Access and Query OSUWMC Cache Tables"
  Set swagger.info.version = "0.1"
  Set swagger.host = "intengtest"
  Return ..%ProcessResult($$$OK, swagger)
}

}

That helped. I was able to get my first two Method's called; however, I am struggling now with passing a value into the message.

<Routes> 
    <!-- Server Info -->
    <Route Url="/" Method="GET" Call="GetInfo" />
    <Route Url="/GetAllEpicDepartments" Method="GET" Call="GetAllEpicDepartments" />
    <Route Url="/GetEpicDepartment" Method="GET" Call="GetEpicDepartment" />
</Routes>
ClassMethod GetEpicDepartment(ID As %String) As %Status
{
    SET tSC = $$$OK
    set sql = "SELECT ID as DepartmentID, Abbr, Name, ExternalName, PhoneNumber, ApptPhone, FaxNumber, Address1, Address2, City, Zip, Specialty, RevLocID, RevLocName, BuildingCategoryID, BuildingName, DepCategoryTypeID, DepType, Center, EAFParent, CostCenter FROM osuwmc_Epic_Clarity.DepartmentMaster WHERE ID = ?"
    do ##class(%ZEN.Auxiliary.jsonSQLProvider).%WriteJSONFromSQL(,,sql,ID)
    return tSC
}

When I try to pass... https://intengtest/api/mgmnt/v1/TESTCLIN/spec/TableLookup/GetEpicDepartment/{ID} into postman I get the following...

{
    "errors": [
        {
            "code": 5002,
            "domain": "%ObjectErrors",
            "error": "ERROR #5002: ObjectScript error: <REGULAR EXPRESSION>PatternSet+4^%Regex.Matcher.1",
            "id": "ObjectScriptError",
            "params": [
                "&lt;REGULAR EXPRESSION&gt;PatternSet+4^%Regex.Matcher.1"
            ]
        }
    ],
    "summary": "ERROR #5002: ObjectScript error: &lt;REGULAR EXPRESSION&gt;PatternSet+4^%Regex.Matcher.1"
}

Creating a REST Service within InterSystems is rather a new concept for me since I am used to the Interoperability (HL7, JDBC, etc..) world. I found some examples out on Open Exchange and other posts that I am trying to figure out how I can mold it into something appropriate for this Use Case.

The Enterprise Application Developers (Web Team) that develop our External Patient facing Applications are not used to trying to connect to something other than Microsoft SQL from .Net. So, trying to find a way to expose this via a REST application would be helpful and less time consuming then trying to figure out the InterSystems Drivers to connect via ODBC/JDBC from .Net.

That is why this was concerning; I didn't want to grant %Development to this new user I was going to create for this purpose. Any suggestions on what else I could do?

Scott Roth · Dec 30, 2025 go to post

I ended up taking the QuickStream response, and creating a dynamic object from the JSON in the quick stream to parse it apart.

Scott Roth · Dec 30, 2025 go to post

Using a variable, I created a bunch of IF Statements to either append to the end of the variable or add value to the variable. Once I went through all the necessary fields, I set target.Request.QueryString = the variable.

Scott Roth · Dec 30, 2025 go to post

This has been resolved. Working with another Hospital System we combined our efforts and came up with Code to take the Encoded HL7 Response, decode, and parse it apart to handle the ACK/NCK.,