Question
· May 29, 2020

Trying to send information from %CSP.REST extended class to a Business Process

I've got a REST service that I can access via a browser. I can get it to take HTML tags as data and display it back to me (so I know the REST part is working). So if I send it this:

http://MyServer:57772/TestArea/rest/TestQuery?UUID=1&RTX=RTX123456&CareType=Palliative
 

Then I can pick out the data and tell it to display in the browser, which is great but what I really want to do is put the data into a string and send to a business process that will do lots of looking up but eventually return a URL that my REST service will then redirect the browser to.

Been trying to follow advice from here but something isn't working as all I get is ERROR #5002.

 /// TestArea's Dispatch class for all REST Services
Class REST.Dispatch Extends %CSP.REST
{ XData UrlMap [ XMLNamespace = "http://www.TestArea.com/urlmap" ]
{
<Routes>
<Route Url="/TestQuery" Method="GET" Call="TestQueryString" />
</Routes>
} ClassMethod TestQueryString() As %Status
{
Set tSC = $$$OK if 'tSC Quit tSC
Set tProxy = ##class(%ZEN.proxyObject).%New()
Set tProxy.UUID = $Get(%request.Data("UUID",1))
Set tProxy.RTX = $Get(%request.Data("RTX",1))
Set tProxy.CareType = $Get(%request.Data("CareType",1))

Set tTextOut = ##class(Ens.StringContainer).%New()
Set tTextOut = tProxy.UUID_"|"_tProxy.RTX_"|"_tProxy.CareType

// Need to create a temporary Service to use to call and get the response from
// our Business Process.

Set tSC = ##class(Ens.Director).CreateBusinessService("Strata JSON Service",.tService)

Set message = ##class(Ens.StringContainer).%New(tTextOut)
Set targetName = "StrataJSON2URLBP"
Set response1 = ##class(Ens.StringContainer).%New()
Set timeout = -1
Set description = "Strata URL"

Set tSC = tService.SendRequestSync(targetName, message, .response1, timeout, description)


Set %response.redirect = response1

Quit $$$OK
}

}

The Business Process StrataJSON2URLBP exists but is fairly sparse at the moment so I suppose the error could also be in there. Let me know if you want that posting.

The error response if that helps:

{
	"errors":[ {
			"code":5002,
			"domain":"%ObjectErrors",
			"error":"ERROR #5002: Cache error: <INVALID OREF>zTestQueryString+28^REST.Dispatch.1",
			"id":"CacheError",
			"params":["<INVALID OREF>zTestQueryString+28^REST.Dispatch.1"
			]
		}
	],
	"summary":"ERROR #5002: Cache error: <INVALID OREF>zTestQueryString+28^REST.Dispatch.1"
}
Discussion (5)0
Log in or sign up to continue

Many thanks for the fast response Eduard.

I should point out I don't have a lot of InterSystems coding experience but I do have a fair amount of general programming experience.

"Check that tSC is not an error"

I'm not sure I fully understand what you're saying by that, however that might not be an issue because:

If ($IsObject(tService))
{
Set tSC = tService.SendRequestSync(targetName, message, .response1, timeout, description)
} Else {
WRITE "No object"
}

Returns "No object" which looks like a smoking gun to me.

So given I've been working from examples that use tService but don't show how to create the object do I need to programatically create it as an object and if so how?

Yeah like I said I don't have a lot of InterSystems coding experience but the guy who does is off!

Well this was a voyage of discovery!

In an attempt to avoid a "rest of the owl" situation I'll show my working out and try and keep it brief.

The problem was I'd read the tool tip for CreateBusinessService and thought the first part was a description but, in fact, it requires an actual Business Service name.

For this I needed to extend Ens.BusinessService with my own.

Class RESTful.RESTfulBusService Extends Ens.BusinessService
{
Property TargetName As %String(MAXLEN = 200);
Parameter SETTINGS = "TargetName:Basic:selector?multiSelect=0&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";
Method OnProcessInput(pInput As %Library.RegisteredObject, pOutput As %Library.RegisteredObject) As %Status
{ Set SC =..SendRequestSync($piece(..TargetName,",") ,pInput, pOutput, 0, "") Quit $$$OK
}
}

Creating that in the Management Portal -> Ensemble -> Configure -> Production as a new Business Service called "RESTfulURLService".

Also (for completeness) I needed to extend request and response for my messages.

Class RESTful.REST2BPRequest Extends Ens.Request
{
Property UUID As %String(MAXLEN = 20);
Property PatNum As %String(MAXLEN = 20);
Property CareType As %String(MAXLEN = 100);
}
Class RESTful.REST2BPResponse Extends Ens.Response
{
Property ResponseURL As %String(MAXLEN = 2500);
}

The final Dispatch Class code then looks like this:

Class RESTful.Dispatch Extends %CSP.REST
{ XData UrlMap
{
<Routes>
<Route Url="/QueryString" Method="GET" Call="ProcessQueryString" />
</Routes>
}
ClassMethod ProcessQueryString(pRequest As RESTful.REST2BPRequest, pResponse As RESTful.REST2BPResponse) As %Status
{
Set tSC = $$$OK if 'tSC QUIT tSC
Set pRequest = ##class(RESTful.REST2BPRequest).%New()
Set pRequest.UUID = $Get(%request.Data("UUID",1))
Set pRequest.PatNum = $Get(%request.Data("PATID",1))
 
Set pRequest.CareType = $Get(%request.Data("CareType",1)) Set tSC = ##class(Ens.Director).CreateBusinessService("RESTfulURLService",.tService)
If $$$ISERR(tSC)
{
     write $System.Status.GetErrorText(tSC), !
     quit tSC
}
Set targetName = "BPReturnURL" //The name of the Business Process I want to call
Set timeout = 30
Set description = "Call to get URL" If ($IsObject(tService))
{
Set tSC = tService.SendRequestSync(targetName, pRequest, .pResponse, timeout, description)
Else {
WRITE "No Object"
}
Set %response.Redirect = pResponse.ResponseURL Quit $$$OK
}
}

The Business Process BPReturnURL accepts my extended Request class and responds with the extended Response class.

This is my first post Eduard so I'm not sure what the etiquette is. Should I mark your post as correct as it lead me to realise where the problem was or this one as it contains the working code?

Either way thanks for pointing me in the right direction.