Throwing custom errors is a really handy tool to have!

You can also take this a step further and if you have code that returns a status (either built in functions such as %Save() or custom errors like you have here), you can deconstruct the status object to get into a nice output string using $System.Status.DecomposeError(). This is especially useful because functions like %Save() don't actually throw the errors again to the caller, they just return the status code from the error thrown within %Save(), so a try/catch won't catch these.

Take, for instance, the following test class. Notice the property on the class is of type %Integer, but in the class method I attempt to set the value to a string. This will cause an error when using %Save():

Class ErrorTest extends %Persistent {
    Property TestProp As %Integer;

    ClassMethod ErrorTest()
    {
      set objectReference = ..%New()
      set objectReference.TestProp = "Test"
      set status = objectReference.%Save()
      if status '= 1 {
        do $System.Status.DecomposeStatus(status,.errorlist)
        for errornum = 1:1:errorlist {
          write !,"Error entry ",errornum,":"
          write !,errorlist(errornum)
        }
      }
    }
}

If I were to wrap the %Save() call in a try/catch, it wouldn't catch the error thrown by the invalid property type when %Save is called. Using the method above, when I run the code I get this:

USER> do ##class(Custom.Robbie.ErrDecomposeTest).ErrorTest()

Error entry 1:
ERROR #7207: Datatype value 'Test' is not a valid number
> ERROR #5802: Datatype validation failed on property 'Custom.Robbie.ErrDecomposeTest:TestProp', with value equal to "Test"


So, when you're using any kind of status, whether it be errors statuses returned by built in functions or custom made error statuses, you can use this to decompose them and get at the various pieces within if the error status isn't actually thrown to be caught by a try/catch.

Presuming that you're trying to script input into a menu-driven routine to generate data or perform some action, the best course of action would be to analyze the code of the legacy menu routine and see what it is calling to actually generate data or perform the action based on the menu input and have your endpoint call that code directly with the proper inputs from your REST endpoint, bypassing the need for the menu and any scripted input. 

Thank you for the responses so far, I greatly appreciate them!

I found some information online about using ADO and ODBC to make the connection which has gotten me close. Here is what I have in Excel VBA:

and here is the error I get when I run this code:

The "GETSQLLBIMA7" query exists in the USER namespace under the USER package. I'm not sure where "SQLUSER" is coming from or how to specify a different namespace or package.

Thank you both for your responses, I greatly appreciate the help!

I tried going down the ODBC route using ADO based on some other information I have found and I seem to be getting hung up by something not getting specified in the call to Cache through ODBC. Here's what I have in the Excel VBA:

When I try to run this, I get this error:

The Query "GETSQLLBIMA7" exists in the USER namespace under the USER package. I'm not sure how to specify to look under USER rather than SQLUSER when calling Cache.