Capturing HTTP 400/500 responses

Discussions related to HTTPAPI (An HTTP Client Package for RPG programming.) http://www.scottklement.com/httpapi/
Post Reply
garwynn
Posts: 3
Joined: Mon Apr 11, 2022 3:58 pm

Capturing HTTP 400/500 responses

Post by garwynn »

I'm doing a POST operation to consume an API, and capturing the response:

Code: Select all

response = http_string('POST':URL:json:'application/json');
I also have a monitor on there for an error.

Everything works great with an HTTP 200 response. I get the response as I'm expecting it.
But if the API fails validation, they send back an HTTP 400. How can I capture the error details?
I ran it in debug mode, it hits the on-error but I checked response and didn't see data in the field.

I set http_debug to *ON and it captures the details here. Here's an example.
Would welcome any suggestions on how to get this so I can at least log it in our log PF instead of going to each debug log file.

Code: Select all

SetError() #13: HTTP/1.1 400 Bad Request
recvresp(): end with 400
recvdoc parms: identity 1083
header_load_cookies() entered
recvdoc(): entered
SetError() #0:
recvdoc(): Receiving 1083 bytes.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected token . in JSON at position 193<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at parse (/home/ubuntu/services/http-integration-service/source/node_modules/body-parser/lib/types/json.js:89:19)<br> &nbsp; &nbsp;at /home/ubuntu/services/http-integration-service/source/node_modules/body-parser/lib/read.js:121:18<br> &nbsp; &nbsp;at invokeCallback (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:224:16)<br> &nbsp; &nbsp;at done (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:213:7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:273:7)<br> &nbsp; &nbsp;at IncomingMessage.emit (events.js:412:35)<br> &nbsp; &nbsp;at endReadableNT (internal/streams/readable.js:1334:12)<br> &nbsp; &nbsp;at processTicksAndRejections (internal/process/task_queues.js:82:21)</pre>
</body>
</html>
Scott Klement
Site Admin
Posts: 652
Joined: Sun Jul 04, 2021 5:12 am

Re: Capturing HTTP 400/500 responses

Post by Scott Klement »

Hello garwynn,

If you change your call to use http_req() the output will be saved. For example you might code it like this:

Code: Select all

dcl-s retry ind inz(*off);
dcl-s rc int(10);

.
.

dou retry = *off;
        
   rc = http_req( 'POST'
                : URL
                : *omit
                : response
                : *omit
                : json
                : 'application/json');

   retry = *off;

   select;
   when rc = 1;
     // successful.  'response' contains results.
   when rc >= 300 and rc <= 399;
     // redirect requested. Get the new URL and try again
     URL = http_redir_loc();
     retry = *on;
   other;
     // request failed.
     // 'response' will contain any error data sent back 
     //   from the server.
   endsl;

enddo; 
In your example, rc will be 400, and the variable named 'response' will contain the following.

Code: Select all

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected token . in JSON at position 193<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at parse (/home/ubuntu/services/http-integration-service/source/node_modules/body-parser/lib/types/json.js:89:19)<br> &nbsp; &nbsp;at /home/ubuntu/services/http-integration-service/source/node_modules/body-parser/lib/read.js:121:18<br> &nbsp; &nbsp;at invokeCallback (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:224:16)<br> &nbsp; &nbsp;at done (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:213:7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (/home/ubuntu/services/http-integration-service/source/node_modules/raw-body/index.js:273:7)<br> &nbsp; &nbsp;at IncomingMessage.emit (events.js:412:35)<br> &nbsp; &nbsp;at endReadableNT (internal/streams/readable.js:1334:12)<br> &nbsp; &nbsp;at processTicksAndRejections (internal/process/task_queues.js:82:21)</pre>
</body>
</html>
Sadly, they are sending the error in HTML format (JSON would be much nicer and a 'best practice' -- but I can't control what the people who run the server send you.) But, it's still readable.
garwynn
Posts: 3
Joined: Mon Apr 11, 2022 3:58 pm

Re: Capturing HTTP 400/500 responses

Post by garwynn »

Scott,

Thanks for the quick response. Originally went http_req because that's what we have used in the past, but was getting a RNF7535 - and since I couldn't solve that I changed to the http_string (and that compiled.)

Details on RNF7535:

Code: Select all

*RNF7535 30        031200  The type and attributes of parameter 4 do not match those of the prototype.
Response is defined as 5000A. JSON was varying, so I tried creating APIResponse to use instead of response. Still didn't resolve the error.

Code: Select all

     DJSON             s          32768    varying
     DAPIResponse      s          32768    varying
http_req code:

Code: Select all

         rc = http_req( 'POST'
                : URL
                : *omit
                : APIResponse
                : *omit
                : json
                : 'application/json');

Prototype from LIBHTTP/HTTPAPI_H, as captured by compile log.

Code: Select all

D http_req        PR            10i 0 opdesc                                
D   Type                        10a   varying const                         
D   URL                      32767a   varying const                         
D   ResultStmf                5000a   varying const                         
D                                     options(*varsize:*omit)               
D   ResultStr                     a   len(16000000) varying                 
D                                     options(*varsize:*omit:*nopass)       
D   SendStmf                  5000a   varying const                         
D                                     options(*varsize:*omit:*nopass)       
D   SendStr                       a   len(16000000) varying const           
D                                     options(*varsize:*omit:*nopass)       
D   ContentType              16384A   varying const                         
D                                     options(*varsize:*omit:*nopass)       
garwynn
Posts: 3
Joined: Mon Apr 11, 2022 3:58 pm

Re: Capturing HTTP 400/500 responses

Post by garwynn »

Resolved by just defining exactly as in the definition, I'll move it to response from there.
Scott Klement
Site Admin
Posts: 652
Joined: Sun Jul 04, 2021 5:12 am

Re: Capturing HTTP 400/500 responses

Post by Scott Klement »

garwynn wrote: Mon Apr 11, 2022 5:59 pm Details on RNF7535:

Code: Select all

*RNF7535 30        031200  The type and attributes of parameter 4 do not match those of the prototype.
Response is defined as 5000A. JSON was varying, so I tried creating APIResponse to use instead of response. Still didn't resolve the error.

Code: Select all

     DJSON             s          32768    varying
     DAPIResponse      s          32768    varying
It can be called "response" or "APIResponse", it doesn't matter.

RPG has two different VARYING types. One has a 2-byte length at the start of it, the other has a 4-byte length. If you don't specify one or the other (you just say 'varying' as you did in your example) it will use a 2-byte length for fields that are 65535 characters or smaller, and 4-byte for anything larger. This is because you can only store numbers as high as 65535 in 2 bytes.

So to fix your problem, you just have to tell RPG to use a 4-byte prefix like this (fixed format):

Code: Select all

     DJSON             s          32768    varying(4)
     DAPIResponse      s          32768    varying(4)
Or in free format:

Code: Select all

dcl-s JSON varchar(32768: 4);
Glad I could help! If you have other questions (including those about defining things so they work with the prototypes) please feel welcome to ask!
Post Reply