How can I pass multiple parameters to an Ensemble REST service and return an authorization token as a response JSON message
This question came on the Ensemble in Healthcare email list. It's a great question. I'm working on an answer, but am posting it here to get any other input. I'll also address the option of using %CSP.REST.
Hello everyone,
Using Intersystems Healthshare/Ensemble, I am trying to make a RESTful Interface between Android/iOS app and Cache database. I have some queries and I am unable to find where exactly I can get any resources on them.
1. By extending the EnsLib.REST.Service class, I have so far made some basic methods like if the interface receives and email ID via a GET request, it checks if its exists in the database and pulls out the password for the account. However, I want to know if we can send back some sort of authorization token or api key as part of the JSON response packet, as a way of notifying the user that his account is authenticated? Also, the key or token will be stored in the mobile cache and used for further calls from the app.
2. Till now, to test the service I so far developed, I am calling the interface by a URL as follows -
http://localhost:57772/myDemo/myService/myApp/UserAccounts/abc@gmail.com
But as you can see I am able to pass only one parameter (which is the email ID at last). I wanted to ask what if I have multiple parameters?
I guess I can restructure the URL something like this ->
http://localhost:57772/myDemo/myService/myApp/UserAccounts/:emailID/:password/:signInType/:socialNetID
But is there any alternative to this? For example, what if I want to receive a JSON request packet (which will have these parameters) and then parse it to extract these parameters and then call my service appropriately? Can this be done?
3. I want to provide this basic interface to the app developers, just for testing purposes. I want to know if there exists some kind of testing environment, so that I can share the URL with developers and they can make the calls to test it. The developers would be accessing the interface remotely (not from the same network which I am connected to).
Any help would be appreciated. Thanks!
The above queries are from me. Let me know if any additional information is required.
Thanks Joshua for the support.
For your second question, you might find this post at Stack Overflow useful.
Great link Scott. Thanks!
Hi Scott,
I am a newbie here, so my queries are a little basic.
I tried to change the format of URL like this http://localhost:57772/myDemo/myService/UserAccounts?email=abc@gmail.com
But, then I get an error in my service which is s follows:
ERROR <Ens>ErrGeneral: Unsupported REST URL: /UserAccounts%3Femail%3Dabc%40gmail.com for HTTP command GET
Can you tell me why this didn't work?
Thanks
For query parameters you'd use the syntax <url>?param=value, e.g.
/appName/customers?lastName=Slagman&gender=M
In your <route> the url would be:
And in your method you'd use:
Hi Herman,
I tried to modify my code as per your suggestions. The URLinside route is set to /UserAccounts. But, it didn't work. I have added trace elements to check what I receive.
The _tEmailID element for which I used the %request.Get, it does not receive the parameter passed to it.
The Event log for service shows that _tEmailID is empty.
Can you have a look at my method and suggest anything if I have missed? Is it required to add any library to use %request?
{
set status = $$$OK
try{
SET tEmailID = %request.Get("account")
$$$TRACE("tEmaildID = "_tEmailID)
ZNSpace "INSTATEMPNS"
&sql(SELECT EmailID,Password INTO :email,:pwd FROM InstaTemp.ISAccounts WHERE EmailID = :tEmailID )
$$$TRACE("email = "_email)
set tProxy = ##class(%ZEN.proxyObject).%New()
IF SQLCODE'=0
{
set tProxy.Email = tEmailID
set tProxy.Pwd = "no password"
set tProxy.SqlCode = SQLCODE
}
ELSE
{
set tProxy.Email = email
set tProxy.Pwd = pwd
set tProxy.SqlCode = SQLCODE
}
//set tProxy = ##class(%ZEN.proxyObject).%New()
//set tProxy.Email = email
//set tProxy.Pwd = pwd
// You could just write the output manually or use helper methods like ..ObjectToJSONStream() to generate JSON
do pOutput.SetAttribute("Content-Type","application/json")
do pOutput.Write("[")
Set tOut=##class(%IO.StringStream).%New()
do ..ObjectToJSONStream(tProxy,.tOut)
do tOut.Rewind()
do pOutput.Write( tOut.Read() )
do pOutput.Write("]"_$C(13,10))
} catch (e) {
set status = e.AsStatus()
}
quit status
}
I'm sorry, I missed the Ensemble part.
I was referring to the %CSP.REST class.
I don't know what version of Ensemble you use, but at least in 2015.1 it seems that the Enslib.REST.Service doesn't copy the %request.Data values (the query parameter values) into the attributes of the pInput stream.
But at least they should be available to you in the %request.Data array (accessible by %request.Get(var)), why that is the case in your situation I can't see, it has got nothing to do with your method, but somewhere 'upstream'.
Hi Herman,
I also tried SET tEmailID = $Get(%request.Data("account",1)). But even then, tEmailID comes up empty in the trace.
I am using HealthShare 2015.2.1
Any ideas?
I'm afraid this will have to be a WRC call: how to get to query parameters in EnsLib.REST.Service
I don't know why the %request doesn't hold the query parameters, maybe it's not even the same request that actually entered the application.
Just a thought. Did you try the values coming in %request.CgiEnvs?
Yes, I tried that too. It also does not takes the value of query. Checking with $$TRACE, tEmaildID still turns out to be empty.
Hi,
I had the same case because I don't use %CSP.REST, so I used the code below to get the parameters of the URL.
URL: http://ipbrdmzvlx163:9980/teste/api/v1/person?type=val&card=gold&type=phill
Set param1=$Get(pInput.Attributes("URL")) $$$LOGERROR("param1: "_param1)
Set param2=$Get(pInput.Attributes("Params","type",1)) $$$LOGERROR("param2: "_param2)
Set param3=$Get(pInput.Attributes("Params","card",1)) $$$LOGERROR("param3: "_param3)
Set param4=$Get(pInput.Attributes("Params","type",2)) $$$LOGERROR("param4: "_param4)
Event Log
')+'
'; content += ''; return content; }, "modalShow": function() { // add ensExceptionModalGroup to class for floating div var modalGroup = EnsException.modalGroup; if (modalGroup) { var div = modalGroup.getFloatingDiv(); if (div) div.className += ' ensExceptionModalGroup'; } // override default behaviour -- user must make a choice var mouseTrap = document.getElementById('zenMouseTrap'); if (mouseTrap) mouseTrap.onmouseup = null; }, "modalDelete": function() { // clean up floating div var modalGroup = EnsException.modalGroup; if (modalGroup) { var div = modalGroup.getFloatingDiv(); if (div && div.parentNode) { div.parentNode.removeChild(div); } } } } window.zenUserExceptionHandler = EnsException.exceptionHandler;Doc: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...