Perfect ! Thanks very much Dmitry :)
- Log in to post comments
Perfect ! Thanks very much Dmitry :)
Hi guys,
Tagging you both for your expert advise :)
@Dmitry Maslennikov @Eduard Lebedyuk
Cheers,
Utsavi
Thanks Dmitry
Thanks Dmitry:) that actually works for me too if i change my route from /patients/{patientRef} to /patients/(.*) in the dispatch class.
My only problem now is that my api specification says the route is /patients/{patientRef} and because we are using the iris api/mgmnt api to auto generate rest classes based on Swagger specification, my dispatch class is auto generated based on .spec class. My .disp class also gets overwritten everytime my .spec class is recompiled. Any ideas on how to get around this?
Many thanks,
Utsavi
Thanks Dmitry:) that actually works for me too if i change my route from /patients/{patientRef} to /patients/(.*) in the dispatch class.
My only problem now is that my api specification says the route is /patients/{patientRef} and because we are using the iris api/mgmnt api to auto generate rest classes based on Swagger specification, my dispatch class is auto generated based on .spec class. My .disp class also gets overwritten everytime my .spec class is recompiled. Any ideas on how to get around this?
Many thanks,
Utsavi
Thanks for the quick response Eduard. Its just the default Apache sever that comes with IRIS. How do I check/change AllowEncodedSlashes setting?
Bumping this up in case anyone has any other solutions.
Hi Eduard,
I am running in the same issue as Dan and trying out your solution in assumption that there is no other better way of handling this. Overriding OnPreDispatch doesn't seem to work for me. My URL seems decoded by then.
E.g. my API URL is
http://localhost:52773/mapi/admin/v1/patients/{patientReference} where patientReference contains a slash so client call would be something like
http://localhost:52773/mapi/admin/v1/patients/ipm%2F3245678
In my OnPreDisptach pUrl is already decoded
v1/patients/ipm/3245678
hence your solution doesn't seem to work. Am I missing something? Is there any other way of handling this?
Thanks,
Utsavi
Thanks Jeffrey. <alert> was it. Do you know if there is a way of catching errors in a DTL ?
Hi Tom,
How do you trigger Ens.Alert from <catchall> in your Business process? Is there a marco available to do so ?
Thank you Marc and Eduard for your reply. After spending some time I figured what you both have pointed i.e the class needs to be persistent.
Hi Eduard,
regarding your comment around moving JSON parsing to BS, is there a reason for doing so?
I have a common business service which can invoke multiple different Business processes based on a parameter. that is why it uses the common class mapi.core.msg.rq.RestBusinessServiceRequest to pass on request data to the BP and let BP do the specifics.
Regards,
Utsavi
Hi Nigel,
Thank you for taking time out to find a solution for this.I'd certainly follow your lead. Is it possible to email me the classes at utsavi.gajjar@mater.org.au ? Thanks again.
Regards
Thanks Dmitry.
Hi Dmitry,
Thanks for this article. Do you know how to read the Authorization Header in the `.disp` class and pass it onto the `.impl` class?
As you have mentioned in the article, `.disp` class is auto-generated by `.spec` class and does get over-written everytime `.spec` class is compiled. This makes it tricky to modify the `.disp` class to add some code to get the Authorization Header. Are you aware of any other ways to get the header ?
Thanks,
Utsavi
Oh that is Perfect mate !! Thanks so much :)
Hi Dmitry,
I am trying out the sample code you supplied. It seems that you have to supply a Secret Key in order to decode the token using ##class(%OAuth2.JWT).JWTToObject(). If I put my sample token on jwt.io , it decodes it without me having to supply the key.
Can we decode the token from IRIS without having to supply the public or private key ?
Thanks a lot Dmitry. I will follow your example code and see if that works for me. Will update you on how I go.
Hi Dmitry,
Thanks for your reply. Yes the OAuth2 token. I haven't setup anything for OAuth2 on IRIS end. In our case, the REST APIs we are building in IRIS are exposed to consumer apps via IAM and Azure. IAM takes care of the OAuth2 Authentication. Client Request then flows through to IRIS which is when I need to introspect the access token to read the "Scope".
I came across the following method, is that something I can utlise?
set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("demoresource",accessToken,.jsonObject)Hi Peter,
I know its an old post but would you mind sharing what does your "do ##class(setup.rCompileAll).doit()" method or the enitre setup.rCompileAll class look like ?
regards
Thanks Evgeny for your reply and also for sharing the links with useful content :)
Regards
Hi there,
Thank you for the video. It talks about using ZPM to package your code and publish on a registry. Are there any links available that talk about "How we can utilise ZPM for organization's internal build and deployment process?
Thanks,
Utsavi
I see what you mean. At this stage, the plan is not to store any data in IRIS. We are trying to implements Intersystems API Manager and it can only talk to IRIS hence using IRIS to write the APIs.
ah well, in our case IRIS is acting as an ESB. Data doesn't live in IRIS. We are calling out to other systems to get the data e.g. Patient Administration System or Health Provider Directory. In this case the other systems may or may not support APIs in which case we would query them using ODBC Adaptor, transform data to FHIR compliant json schema in IRIS and return to the client.
Hi Dmitry,
Thank you for reply :)
>>>Speaking about HealthCare application, why would you even decide to implement some own way, when FHIR already covers most of the things you would need?
Would you mind elaborating on this last statement please? I am not sure what you mean.
We are writing specifications for our API following the FHIR standard.
Utsavi
I have posted a question for advise on best practices when developing REST APIs and Production using IRIS.
https://community.intersystems.com/post/best-practices-implementing-res…
Would you mind providing your thoughts please? thanks
Thank you for the tip! Its working well.
Hi Eduard,
Firstly, thank you for sharing this article. Great information !
I am trying to work out best way of Error Handling within a REST Business Operation and Business Process. My Business Operation makes a call to the third party API to do certain things. I need to return the response I get back from the third party to the clinet. Possible repsonses are,
- 200 in which case I return requested data e.g. Patient demographics
- 404 Patient not found
- 500 - Internal Server Error
This is what my Business Operation currently looks like,
Code
Class rest.admin.bo.GetPatient Extends EnsLib.REST.Operation
{ Parameter INVOCATION = "Queue"; /// remove URL from SETTINGS
Parameter SETTINGS = "-URL";
Method GetPatient(pRequest As rest.admin.msg.rq.Patient, Output pResponse As rest.admin.msg.rp.Patient) As %Status
{
set tSC = $$$OK
try {
set HTTPrequest=##class(%Net.HttpRequest).%New()
set HTTPrequest.Https=1
set HTTPrequest.SSLConfiguration=..Adapter.SSLConfig
do HTTPrequest.SetHeader("Accept","application/json")
do HTTPrequest.SetHeader("Authorization","Bearer "_pRequest.AuthToken)
// Set URL PArameters
do HTTPrequest.InsertParam("urn",pRequest.urn)
// Issue the call
set tSC=..Adapter.SendFormData(.tHttpResponse, "GET", HTTPrequest)
// Instantiate the interoperability response object
set pResponse = ##class(rest.admin.msg.rp.Patient).%New()
set pResponse.HttpStatusCode = tHttpResponse.StatusCode
set pResponse.HttpStatusText = $$$StatusDisplayString(tSC)
// Handle an error condition
If $$$ISERR(tSC) {
if $IsObject(tHttpResponse)&&$IsObject(tHttpResponse.Data)&&(tHttpResponse.Data.Size) {
Set tSC=$$$ERROR($$$EnsErrGeneral,$$$StatusDisplayString(tSC)_":"_tHttpResponse.Data.Read())
}
} else {
// Status=200.
If $IsObject(tHttpResponse)&&$IsObject(tHttpResponse.Data)&&tHttpResponse.Data.Size {
// use JSON Import capabilities to correlate JSON stream to properties.
do pResponse.%JSONImport(tHttpResponse.Data) // Set values additional properties here if needed
}
}
} catch{
Set tSC=$$$SystemError
} Quit tSC
} XData MessageMap
{
<MapItems>
<MapItem MessageType="rest.admin.msg.rp.Patient">
<Method>GetPatient</Method>
</MapItem>
</MapItems>
} }Now, when the BO gets any sort of error, the operation shows an error and so does the process and same error goes back to the clinet e.g. in event of 503 client sees,
JSON
{
"errors": [
{
"code": "<Ens>ErrGeneral",
"domain": "Ens",
"error": "ERROR <Ens>ErrGeneral: ERROR <Ens>ErrHTTPStatus: Received non-OK status 503 from remote HTTP server: 'HTTP/1.1 503 Service Unavailable':<html><body><b>Http/1.1 Service Unavailable</b></body> </html>",
"id": "EnsErrGeneral",
"params": [
"ERROR <Ens>ErrHTTPStatus: Received non-OK status 503 from remote HTTP server: 'HTTP/1.1 503 Service Unavailable':<html><body><b>Http/1.1 Service Unavailable</b></body> </html>"
]
}
],
"summary": "ERROR <Ens>ErrGeneral: ERROR <Ens>ErrHTTPStatus: Received non-OK status 503 from remote HTTP server: 'HTTP/1.1 503 Service Unavailable':<html><body><b>Http/1.1 Service Unavailable</b></body> </html>"
}I need to catch this exception and modify the json response that goes back to the client. But I am not sure what is the best way to do that. Is it something that is best done in BO or BP ?
Any help or guidance on this will be much appreciated!
Utsavi
Hi Eduard,
I am looking for some examples of REST API served through production. Would you be able to point me to some, please?
I am trying to implement a business service, process and operation that serves bundle of apis related to a domain and resource e.g Patient , Patient alerts, patient status . These will be 3 api urls served by single business service, process and operation.
I am also looking for best practice to handle various http responses in BP and BO.
Would greatly appreciate if you can direct me to relevant examples.
Thank you,
Utsavi
Thanks Vitaly Furman
We enabled logging on receiving PACS and figured out that Ensemble was sending same ID for 2 different SOP classes. I had been using the "CreateAssociation" command with third argument as blank to create associations. When doing so , Ensemble adds all Abstract Syntaxes it knows about with default TransferSyntax of Implicit VR. I believe the receiving PACS didn't cater for one of the Abstract Syntax.
To solve the problem, I removed the association. Created it using GUI so no default Presentation COntext is added. I then manually added a few Abstract Syntax with Basic Transfer syntax of Implicit VR and retested and this time the communication worked.
I then created an Import file for the PACS based on Conformation Statement provided by PACS and imported in Ensmeble using the ImportAssociation command.
Regards,
Utsavi