Issue returning JSON to the calling URI

Discussions relating to the ScottKlement.com port of the open source YAJL JSON Reader/Generator. This includes the YAJL tool as well as the YAJLR4, YAJLGEN, YAJLINTO and YAJLDTAGEN add-ons from ScottKlement.com. http://www.scottklement.com/yajl/
Post Reply
jarhead0311
Posts: 8
Joined: Wed Dec 21, 2022 4:32 pm

Issue returning JSON to the calling URI

Post by jarhead0311 »

I'm trying to read a row from an SQL, reformat it to a JSON using YAJL and send it back to the calling URI. I'm using Postman for the call and I am getting a 500 status "Internal server error" returned. I know it's finding my RPG program, because I've also added yajl_saveBuf() to save it to the IFS and that part is working.

I'm guessing that the error is with the yajl_copyBufStr() command, or somewhere else that I'm not familiar with. I'm assuming the yajl_copyBufStr() command copies the the buffer to a string variable that I should be able to send using the QtmhWrStout() command.

Here's the code where I'm just trying to send one row from the stored procedure back to the calling URI.

It's a very simple example, here's the program:

Code: Select all

       ctl-opt option(*nodebugio:*srcstmt) dftactgrp(*no)
               bnddir('CPROCTOR/WEB':'YAJL':'QC2LE':'HTTPAPI') decedit('0.');

      /copy httpapi_h

      /include yajl_h

       dcl-pr getenv           Pointer extproc('getenv');
         *N                    Pointer value options(*string);
       end-pr;

       dcl-pr QtmhWrStout      extproc('QtmhWrStout');
         DtaVar                char(65535) options(*varsize) const;
         DtaVarLen             int(10) const;
         ErrorCode             char(8000) options(*varsize);
       end-pr;

       dcl-ds err              qualified;
         BytesProv             int(10) inz(0);
         BytesAvail            int(10) inz(0);
       end-ds;

       dcl-ds row                  qualified;
         sizcod                    char(4);
         sizdsc                    char(25);
         sizsht                    char(5);
         sizseq                    int(5);
         dimseq                    int(5);
       end-ds;

       dcl-s rssizes               SQLTYPE(RESULT_SET_LOCATOR);
       dcl-s success               ind;
       dcl-s errMsg                varchar(500);
     D data            s           5000a   varying
     D uri             s           5000a   varying

       //http_debug(*ON: '/tmp/cproctor-trace.txt');

       uri = %str(getenv('REQUEST_URI'));

       exec sql call sptblsiz;

       if (sqlcode = 466);

         exec sql
           associate result set locators (:rssizes)
             with procedure sptblsiz;

         exec sql
           allocate c1 cursor for result set :rssizes;

         json_start();

         dow sqlstt='00000' or %subst(sqlstt:1:2)='01';

           exec sql fetch next from c1 into :row;

           json_addRow();
         enddo;

         exec sql close c1;

         json_finish();
         json_save();

       endif;

       *inlr = *on;
       return;

       //--------------------------------------------------------------------------------
       // json_start - Start JSON
       //--------------------------------------------------------------------------------
       dcl-proc json_start;

         yajl_genOpen(*ON);

         yajl_beginObj();
         yajl_addBool('success': success);
         yajl_addChar('errmsg': errMsg);
         yajl_beginArray('list');

       end-proc;

       //--------------------------------------------------------------------------------
       // json_addRow - Add a row to the JSON file
       //--------------------------------------------------------------------------------
       dcl-proc json_addRow;

         yajl_beginObj();
         yajl_addChar('sizcod': row.sizcod);
         yajl_addChar('sizdsc': %trim(row.sizdsc));
         yajl_addChar('sizsht': %trim(row.sizsht));
         yajl_addNum('sizseq': %char(row.sizseq));
         yajl_addNum('dimseq': %char(row.dimseq));
         yajl_endObj();

       end-proc;

       //--------------------------------------------------------------------------------
       // json_finish - Finish JSON
       //--------------------------------------------------------------------------------
       dcl-proc json_finish;

         yajl_endArray();
         yajl_endObj();

       end-proc;

       //--------------------------------------------------------------------------------
       // json_save - Save JSON
       //--------------------------------------------------------------------------------
       dcl-proc json_save;

         yajl_saveBuf('/tmp/example.json': errMsg);

         data = yajl_copyBufStr();
         QtmhWrStout(data: %len(data): err);

         yajl_genClose();

       end-proc;       
Any suggestions on how to correct it would be greatly appreciate it. I need to prove out that this is possible.
Scott Klement
Site Admin
Posts: 636
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue returning JSON to the calling URI

Post by Scott Klement »

You have to send back HTTP headers:

Code: Select all

  data = 'status: 200 OK' + x'25'
       + 'Content-type: text/plain' + x'25' + x'25';
  QtmhWrStout(data: %len(data): err);
Also the encoding of your data must be correct for the CgiConvMode you are using.
jarhead0311
Posts: 8
Joined: Wed Dec 21, 2022 4:32 pm

Re: Issue returning JSON to the calling URI

Post by jarhead0311 »

Thank you, Scott. I'm now getting data returned, but it isn't ASCII.

I looked at the httpd.conf file and it had a 'CgiConvMode %%MIXED/MIXED%%' but nothing for the DefaultFsCCSID and DefaultNetCCSID.

When I look at the apachedft job I see these attributes:

CODED CHARACTER SET IDENTIFIER . . . . . . . . . : 65535
DEFAULT CODED CHARACTER SET IDENTIFIER . . . . . : 37

I've searched and found this thread where you mentioned having an issue converting to EBCDIC to ASCII if the header has "application/" in the type, which mine does, I'm sending a JSON file. I've tried adding ccsid(*utf8) to the data variable and sending that in the QtmhWrStout command, but I'm still getting garbage.
Personally, the setup I use is like this:

DefaultFsCCSID 37
DefaultNetCCSID 1208
CgiConvMode %%MIXED/MIXED%%

This tells Apache that my local system is CCSID 37 for EBCDIC (you might want 278 for Sweden, I don't remember) and that the network should be CCSID 1208 (UTF-8). This will cause Apache to translate the data from UTF-8 to EBCDIC when receiving, or from EBCDIC to UTF-8 when sending.

If you leave off the DefaultNetCCSID, it will use CCSID 819, I believe -- and that's not Unicode, it's ASCII.

The other thing I've noticed is that if you use 'text/xml' it will translate it, but 'application/xml' will not. It seems to differentiate between text documents vs. non-text -- and since XML is text, but has 'application' it causes problems. Same for 'application/json'. Therefore, you may need to read into a CCSID(*UTF8) field in your RPG program, and convert it yourself. Depending on the circumstances.
I tried adding the the DefaultFsCCSID and DefaultNetCCSID as you mentioned above as well with no improvement. Any suggestions? Thanks in advance!
Post Reply