Written by

Enterprise Application Development Consultant at The Ohio State University Wexner Medical Center
MOD
Question Scott Roth · Jul 25, 2023

REST API Request Logging

I am working on my first REST operation to send a API Request to an internal server within our Network. I have finally got past the point of being able to connect using a SSL/TLS Configuration, but I am getting a ERROR <Ens>ErrHTTPStatus: Received non-OK status 403 from remote HTTP server: 'HTTP/1.1 403 Forbidden'.

I have tried using $$$TRACE within my operation to capture the different elements that are being sent to verify the Server, URL, SSL Configuration, and payload. Is there a way that I can see the entire RAW request message that is being sent to see why I might be getting a 403 error in response? What is the best way to go about logging the request message to the trace viewer that has the Header and Data elements?

for example using POSTMAN I can see the following.....

POST xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Host: xxxxxxxxxxxxxxxxxx
Epic-Client-ID: xxxxxxxxxxxxxxxxxxxxxx
Proxy-Connection: keep-alive
Accept: application/json
Content-Type: application/json
Authorization: Basic xxxxxxxxx
Content-Length: 119

{"PatientID":"x","PatientIDType":"xxxxxxx","ContactID":"x","ContactIDType":"xxxx","UserID":"xxxx","UserIDType":"xxxxxxx"}

and it sends a response with the same variables that I am using in the Operation, I just want to verify what is being sent in the RAW request to see if I can track down the 403 error.

I get the following response in postman, which is what I expect because I know I didn't send a correct Identifier.

{"Message":"An error occurred while executing the command: NO-PATIENT-FOUND details: No patient was found with the provided ID and ID type..","ExceptionMessage":"An error occurred while executing the command: NO-PATIENT-FOUND details: No patient was found with the provided ID and ID type..","ExceptionType":"System.Web.HttpException","StackTrace":null}

I would like to see if I can get both the RAW request message and the entire response if it is an error to display in the trace viewer.

Thanks

Product version: IRIS 2023.1

Comments

David Hockenbroch · Jul 25, 2023

Does the user you're using to access the API have proper permissions to use the API and the tables that it accesses?

0
Scott Roth  Jul 25, 2023 to David Hockenbroch

I am able to call the API without any issues using POSTMAN using the same username/password.

0
Luis Angel Pérez Ramos · Jul 26, 2023

Hi Scott! What application are you using to send the POST call? Is it a web application? IRIS?

0
Scott Roth  Jul 26, 2023 to Luis Angel Pérez Ramos

IRIS

0
Scott Roth · Jul 27, 2023

The issue was with the Custom Header field I needed for connecting to Epic.

0
Eduard Lebedyuk · Jul 28, 2023

Assuming you are using EnsLib.HTTP.OutboundAdapter, you can do this:

1. In your adapter set DEBUG flag to 1 or 2:

/// This is the debug flag setting (0 do nothing, 1 show request, 2 show request/response)Parameter DEBUG As%Integer = 1;

2. Start BO in foreground.

0
Scott Roth  Jul 28, 2023 to Eduard Lebedyuk

I have tried that but still unable to see the Request or Response being sent...

Class User.REST.Epic.EpicOperation Extends (EnsLib.REST.Operation, Ens.Util.JSON)

{

Parameter DEBUG As %Integer = 2;

Parameter INVOCATION = "Queue";

Method getPatientLocationRequest(pRequest As User.REST.Epic.Msg.GetPatientLocationRequest, Output pResponse As EnsLib.HTTP.GenericMessage) As %Status

{

    set tSC = $$$OK

    try{

      set tHTTPRequest = ##class(%Net.HttpRequest).%New()

      do tHTTPRequest.SetHeader("Epic-Client-ID","ed7ca30e-c16a-4053-9233-bff4f5661bb4")

      $$$TRACE("HttpRequest: "_tHTTPRequest) <this returns me just a pointer 8@%Net.HttpRequest>

      set tRequest = ##class(%DynamicObject).%New()

      set tRequest.PatientID = pRequest.PatientID

      set tRequest.PatientIDType = pRequest.PatientIDType

      set tRequest.ContactID = pRequest.ContactID

      set tRequest.ContactIDType = pRequest.ContactIDType

      set tRequest.UserID = pRequest.UserID

      set tRequest.UserIDType = pRequest.UserIDType

      set reqMsg = tHTTPRequest.EntityBody.Write(tRequest)

      $$$TRACE("reqMsg: "_reqMsg)

      set tSC = tHTTPRequest.EntityBody.Write(tRequest.%ToJSON())

      set tURL = ..Adapter.URL

      set tSC = ..Adapter.Post(tURL)

      set stream = "".....

0
Eduard Lebedyuk  Jul 31, 2023 to Scott Roth

You need to set

Parameter DEBUG As%Integer = 2;

in adapter, not in BO.

You'll get output on the current IO device (that's why you need to run BO in Foreground Mode), when your code gets to this line:

set tSC = ..Adapter.Post(tURL)
0
Scott Roth  Jul 31, 2023 to Eduard Lebedyuk

I enabled DEBUG = 2 on EnsLib.HTTP.OutboundAdapter, but I am still not seeing the entire Request message being sent within the Foreground display that pops up when I execute the Test. 

I was able to $$$LOGINFO(tHTTPRequest.OutputHeaders()) and verified that the header segment is being sent, but it is still throwing a 403 Forbidden error back at me.

0
Eduard Lebedyuk  Jul 31, 2023 to Scott Roth

Could you try DEBUG=1 please?

I think 1 is to show request and 2 is to show response.

0
Scott Roth  Jul 31, 2023 to Eduard Lebedyuk

Does the error mean that I can't do just a POST, I need to use SendFormArray?

Here is my Test code...

0
Eduard Lebedyuk  Jul 31, 2023 to Scott Roth

When you use DEBUG=1 the request is not actually sent, just displayed, so you get downstream errors, ignore them.

First you need to check your request with DEBUG=1, verify that everything is okay and after that switch to DEBUG=2.

With DEBUG=2 the request is sent (but not displayed) and you get response back (which would be displayed).

0
Eduard Lebedyuk  Jul 31, 2023 to Scott Roth

Also you need to pass your tHTTPRequest as pHttpRequestIn (using Send* methods of the adapter) - as currently none of your headers are sent.

0
Scott Roth  Aug 4, 2023 to Eduard Lebedyuk

Not sure I follow... I do all the SetHeader lines, then call  Do tHTTPRequest.EntityBody.Write() is that not writting the headers to tHTTPRequest?

    do tHTTPRequest.EntityBody.Write()
    do tHTTPRequest.OutputHeaders()
    set tURL= "/../../../../"  //..Adapter.URL
    set jsonRequest = {"........."}
    SET tSC = tHTTPRequest.EntityBody.Write(jsonRequest.%ToJSON())
    set tHTTPResposne = ##class(%Net.HttpResponse).%New()
    do tHTTPRequest.OutputParams()
    set tSC = ..Adapter.SendFormDataArray(.tHTTPResposne,"POST",,,tHTTPRequest)
0
Eduard Lebedyuk  Aug 5, 2023 to Scott Roth

It is setting headers, yes. But in your previous sample code you were using ..Adapter.Post method which does not take tHTTPRequest.

0