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?
Comments
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/TableLookupto get the openapi 2.0 information.
Get all REST apps
/api/mgmnt/v1/:namespace/restapps 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": [
"<REGULAR EXPRESSION>PatternSet+4^%Regex.Matcher.1"
]
}
],
"summary": "ERROR #5002: ObjectScript error: <REGULAR EXPRESSION>PatternSet+4^%Regex.Matcher.1"
}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.
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)
}
}