Written by

Enterprise Application Development Consultant at The Ohio State University Wexner Medical Center
MOD
Question Scott Roth · Jan 2

Defining REST API using iris-rest-api-template - Need guidance

Defining my first REST API within InterSystems using iris-rest-Api-template as a basis and I am seeing if someone could provide me some guidance to see if I can make it work.  

In some of my other posts, I have been trying to come up with a way for our Enterprise Application Development team which works with .Net to build Applications to make a REST call to our instance of InterSystems to query some of the Cache Tables we have defined. 

Using the iris-rest-api-template, I have created the osuwmc.DataLookup.REST.Base.cls

Class osuwmc.DataLookup.REST.Base Extends %CSP.REST [ System = 3 ]
{

Parameter CHARSET = "utf-8";
Parameter CONTENTTYPE = "application/json";
Parameter HandleCorsRequest = 1;
Parameter PAGESIZE As INTEGER = 50;
ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status
{
  SET tSC = $$$OK
  TRY {
    
    // Set the return type according to the Accept type in the request. Default is application/json.
    IF ('..AcceptsContentType(..#CONTENTTYPEJSON)) {
      SET tSC = ..ReportHttpStatusCode(..#HTTP406NOTACCEPTABLE), pContinue=0
      QUIT
        } ELSE {   
      // This always returns json
      SET %response.ContentType=..#CONTENTTYPEJSON
        }
        
        
        // read request object into %DynamicObject format
    IF ((pMethod'="POST") && (pMethod'="PUT")) || (%request.Content="") {
      SET %request.Content = {}
    } ELSE {
      IF '$isobject(%request.Content) {
        SET tContent = %request.Content
      } ELSE {
        SET tContent = ""
        WHILE '%request.Content.AtEnd {
          SET tContent = tContent_%request.Content.Read()
        }
      }
      IF (tContent="") {
        SET %request.Content = {}
      } ELSE {
        SET tContent = $zconvert(tContent, "I", "UTF8")
        SET %request.Content = ##class(%Library.DynamicObject).%FromJSON(tContent)
      }
    }
        
  } CATCH ex {
    SET tSC = ex.AsStatus()
  }
  QUIT ##class(%iKnow.REST.Base).%ErrorHandler(tSC, .pContinue)
}

ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ]
{
  #dim %response As %CSP.Response
  SET tSC = $$$OK
  IF $$$ISERR(pStatus) {
    SET %response.Status = 500
    SET tSC = ..StatusToJSON(pStatus, .tJSON)
    IF $isobject(tJSON) {
      SET pResult = tJSON
    } ELSE {
      SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] }
    }
  } 
  ELSEIF pStatus=1 {
    IF '$isobject(pResult){
      SET pResult = {
      }
    }
  }
  ELSE {
    SET %response.Status = pStatus
    SET error = $PIECE(pStatus, " ", 2, *)
    SET pResult = {
      "error": (error)
    }
  }
  
  IF pResult.%Extends("%Library.DynamicAbstractObject") {
    WRITE pResult.%ToJSON()
  }
  ELSEIF pResult.%Extends("%JSON.Adaptor") {
    DO pResult.%JSONExport()
  }
  ELSEIF pResult.%Extends("%Stream.Object") {
    DO pResult.OutputToDevice()
  }
  
  QUIT tSC
}

ClassMethod ReportHttpStatusCode(pHttpStatus, pSC As %Status = {$$$OK}) As %Status
{
  Set %response.Status=pHttpStatus
  
  If $$$ISERR(pSC) Do ..outputStatus(pSC)
  /*
  If (+pHttpStatus>=400) {
    Set %response.ContentType = "application/json"
    SET pResult = {
      "error": ($PIECE(pHttpStatus, " ", 2, *))
    }
    Return ..%ProcessResult($$$OK, pResult)
  }*/
  Return $$$OK
}

}

and the osuwmc.DataLookup.REST.TableLookup

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

Parameter Version = "1.0.0";
Parameter GlobalName = "^OSUWMCDataLookup.TableLookup";
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>  
    <!-- Server Info -->
    <Route Url="/" Method="GET" Call="GetInfo" Cors="true"/>
    <Route Url="/info" Method="GET" Call="GetAllEpicDepartments" Cors="true"/>
    </Routes>
}

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

ClassMethod GetAllEpicDepartments() 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"
    do ##class(%ZEN.Auxiliary.jsonSQLProvider).%WriteJSONFromSQL(,sql)
    return tSC
}

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
}
ClassMethod SwaggerSpec() As %Status
{
  Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger)
  Do swagger.info.%Remove("x-ISC_Namespace")
  Set swagger.basePath = "/crud"
  Set swagger.info.title = "REST API to Access and Query OSUWMC Cache Tables"
  Set swagger.info.version = "0.1"
  Set swagger.host = "intengtest.osumc.edu"
  Return ..%ProcessResult($$$OK, swagger)
}

}

I defined the Web Application as /api/mgmnt/<namespace>/TableLookup with the osuwmc.DataLookup.REST.TableLookup as the Dispatch Class.

When I try to execute the REST call using POSTMAN, "msg": "ERROR #8754: Unable to use namespace: TABLELOOKUP."

If I try to use the sample class, I get a message saying that "The request URL was not found on the server" or a "404 Not Found"

I checked the Web Gateway to make sure the application was defined.

So, am I missing a step somewhere?

Product version: IRIS 2025.1
$ZV: IRIS for UNIX (Red Hat Enterprise Linux 8 for x86-64) 2025.1 (Build 230_2U) Wed Jun 4 2025 18:50:44 EDT [HealthConnect:8.2.2]

Comments

Ashok Kumar T · Jan 2

Hi @Scott Roth 

The /api/mgmnt endpoint was previously used to retrieve OpenAPI 2.0 (Swagger) information for the web application. Therefore, if the web application class (%CSP.REST) is created using the traditional approach (manually created), use.

/api/mgmnt/v1/:namespace/spec/TableLookup

to get the openapi 2.0 information.

Get all  REST apps

 /api/mgmnt/v1/:namespace/restapps 
0
Scott Roth  Jan 5 to Ashok Kumar T

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"
}
0
Enrico Parisi  Jan 5 to Scott Roth

Are you sure that the Routes you posted are the ones used by the called web application?

The error suggest there is an issue (invalid value?) with the Url attribute in the Routes.

You may want to check the generated method DispatchMap in the .int code of your dispatch class.

0
Scott Roth  Jan 5 to Enrico Parisi

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)
}

}
0