Debugging REST API in InterSystems IRIS
Hi developers!
How do you debug implementation code in .impl classes of REST.API in InterSystems IRIS?
Especially if you don't have access to globals, so no things like:
Set^AAA="here we are"not possible in this case.

Suppose I have the following signature of the REST.API method called as POST and containing JSON. :
ClassMethod submitForm(formData As%Stream.Object) As%Stream.Object
{
return formData
}Can I debug "line by line" or "command by command"?
Can I return anything to the browser's console? Or into any IRIS expected place, which is relatively easy to check?
What are my options?
Please, share your experience?
Comments
3 variants come to my mind
- writing to ErrorLog Do LOG^%ETN()
- write to Systrem message.log
set%evgeny=$ioopen1use1write !,"Was in my REST code",! close1use%evgeny - If you have a terminal session LOCK ^%EVGENY --- And into your code, add this simple loop
-
forLOCK +^%EVGENYQUIT:$TESTHANG0.5Now your method loops, and you can attach with any external debugger. Releasing the LOCK from Terminal does the "un-freeze"
Thanks @Robert Cemper ! As always - many options! Will try all
VS Code has a GUI that will help you debug REST services: https://docs.intersystems.com/components/csp/docbook/DocBook.UI.Page.cl…
Thanks @Brett Saviano ! I'll give it a try
Hi @Brett Saviano !
Tried it!
Here is the feedback:
1 - can we add the link to the VSCode extension to be installed? I spent some time before I understood that, besides InterSystems ObjectScript, I need to install a special ObjectScript Extension pack .
2 - to make a REST API call I need to fill all the fields manually. Even I have an Open API spec class. Is it possible to read from it and provide all the fields ready to for tests? Filed a task and an idea.
3. Wasn't able to start debugging: faced the following error:

You can create and log exceptions so that they show up in the application error logs in the SMP. That's how I prefer to do things.
Thanks @David Hockenbroch ! Is it like @Robert Cemper suggests with Do LOG^%ETN()?
@Evgeny Shvarov it's like this:
try{
//Do things here
}
catch ex{
do ex.Log()
return ex.AsStatus()
}If you do this, then the error gets logged in the application error logs in the system management portal, and a JSON representation of the exception gets returned through the API.
Thank you, @David Hockenbroch !
I'll give it a try!
This works like a charm, @David Hockenbroch !
I'd also add to a VSCode a convenient extra link to see all the errors of such like here:
"links": {
"UnitTest Portal": "${serverUrl}/csp/sys/%25UnitTest.Portal.Home.cls?$NAMESPACE=IRISAPP",
"Error Log": "${serverUrl}/csp/sys/op/UtilSysAppErrorNamespaces.csp"
}
Thanks Ed! I’ll take a look!
Hi Ed @Eduard Lebedyuk !
Where do I see this displayed data by:
do ##class(%CSP.Utils).DisplayAllObjects()
?
From Class Docs.:.png)
Somewhere in the CSP page. This is just ~20% of the content.png)
Thanks, @Robert Cemper !
But here I'm more interested in debugging the REST API implementation method, so it is not very useful in this case, right?
YEAH, it's built for visual CSP pages
this may help to get the plain %request object:
k^SPOOLs%io=$I O 2 u 2ZW%request c 2 u %ioor whatever object you need to trace
Thank you, @Robert Cemper !
This works like a charm!
So, in my case, I also wanted to see what's in a stream object that comes into the method (you may ask me how I don't know this, as it is method I coded? ) I don't, as it is a generated one via %^REST):
ClassMethod submitForm(formData As%Stream.Object) As%Stream.Object
{
set formDataObj= {}.%FromJSON(formData.Read())
k^SPOOLs%io=$I O 2 u 2do formDataObj.%ToJSON() c 2 u %ioreturn$$$OKAnd then I do a REST API call and can see data in the terminal with zw ^SPOOL global:
USER>zw ^SPOOL
^SPOOL(1,1)="{""amount"":0,""name"":""John Doe"",""taxid"":""AB123456C"",""nationality"":""british"",""email"":""john.doe@example.com""}"
^SPOOL(1,2147483647)="{67504,40535{2{"Simple and easy! Fantastic, @Robert Cemper !
It is a global, again, though... But a very interesting and useful way to convert any write to a device into a global.
Deserves a one liner input!
Set response type to HTML:
ClassMethod Test()
{
set%response.ContentType = "application/html"do##class(%CSP.Utils).DisplayAllObjects()
quit$$$OK
}In Postman click Preview button:
.png)
Thanks @Eduard Lebedyuk ! I'll give it a try!
Will it work for POST requests too?
And is it for Postman only? E.g. if I use swagger-ui how could I get this page displayed?
It will work with any HTTP request verb.
Most REST dev clients have support for HTML preview, just remember to set Content Type. I don't think swagger-ui can do that as it's not an app, rather a page running in a browser.
Hi @Eduard Lebedyuk !
Unfortunately, this approach is not working (at least for me) while using ^%REST approach and disp->impl implementation classes schema:

If I put this into the impl classmethod, the only thing I'm getting back in Postman is 1:

But I must say Postman seems as a great tool to debug REST API in IRIS, even while debugging local stuff. And it can build collections on the fly on open-api spec provided - very convenient!
Given that the routes in your enabled %CSP.REST class point to class methods you should be able to debug/step thru line by line by calling the class method. In the case where you might have a POST/PUT for your route that calls the class method you can always define the formal specificaiton of the class method to accept parameters and then have the code in your class method look at either your parameter values or %request.Data to determine if the class method is being called by a Http call or your simple debugging.
@Stephen Canzano , when you are testing you can also manually define %request and give it a body and whatever else it needs before you call your class method. For instance:
set%request = ##class(%CSP.Request).%New()
set%request.ContentType = "application/json"set%request.Method = "POST"set%request.Content = ##class(%CSP.CharacterStream).%New()
set json = {}.%New()
set json.firstname = "David"set json.lastname = "Hockenbroch"do%request.Content.Write(json.%ToJSON())
Then you can call your class methods and the %request object you usually manipulate in those methods will be defined.
Wow, thanks @David Hockenbroch !
Is it as simple as that? So when we receive a web call, it is all about the %request with the Method and content filled?
This could also be the way to unit-test REST-API methods
Calling the methods this way is effective for testing the methods, yes. You just want to get really familiar with the %CSP.Request class. This approach isn't a good way to troubleshoot issues with your routes, or with authentication, though, as it bypasses those steps. For that, you'd probably have to define %request appropriately, then call some of the methods your API inherits from %CSP.REST, but I'm not as familiar with those.