ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

HTTPAPI http_string() Variable Definitions

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • HTTPAPI http_string() Variable Definitions

    I'm having difficulty trying to figure out the proper way to interface with the http_string() api and passing in a varying json string. I have the following field definitions:

    Code:
    dcl-s jsonRequest varchar(65535);
    dcl-s jsonRequestLength int(10);
    Here is my execution of http_string():

    Code:
    %len(jsonRequest) = 65535; // could not find a solid example of how changing the len of the request is supposed to work
    rc = yajl_copyBuf( 0                   
                     : %addr(jsonRequest)  
                     : %size(jsonRequest)  
                     : jsonRequestLength );
    %len(jsonRequest) = jsonRequestLength;
    yajl_genClose();                                          
    
    http_debug( *ON : debugFileName );                        
    http_setOption('network_ccsid': '1208');                  
    http_xproc( HTTP_POINT_ADDL_HEADER : %paddr(addAuthOnly) )
    
    monitor;                                                  
      callp http_string( 'POST'                               
                       : serviceUrl                           
                       : jsonRequest                          
                       : 'application/json' );                
    on-error;  
      // handle error
    end-mon;
    
    http_debug( *OFF : debugFileName );
    After executing this code and logging the http_string() request, the json object opening curly bracket ('{') is missing and there are two extra spaces at the end of the json request.


  • #2
    I just added/changed the code to the following and I am still getting the same issue:

    Code:
    dcl-c JSON_REQUEST_MAX_LENGTH const(%len(jsonRequest)); 
    
    %len(jsonRequest) = JSON_REQUEST_MAX_LENGTH;  
    rc = yajl_copyBuf( 0                          
                     : %addr(jsonRequest)         
                     : %size(jsonRequest)         
                     : jsonRequestLength );       
    
    %len(jsonRequest) = jsonRequestLength;
    My http_string() log still shows that the open curly bracket missing and there are 2 extra "special character/hex codes" at the end of the request.

    Comment


    • #3
      Here is the code to build the json (I cannot edit posts, so, sorry for so many responses):

      Code:
      // build request in json format                                    
      yajl_genOpen(*off); // *on = pretty output, *off = condensed output
      yajl_beginObj();                                                   
      yajl_addChar('var1':var1);                            
      yajl_addChar('var2':va2);                                          
      yajl_endObj();

      Comment


      • #4
        (again, sorry for so many posts):

        I realized a mistake in my last code. I was reusing the %size of jsonRequest when I should have been passing JSON_REQUEST_MAX_LENGTH. I corrected the call to http_string as follows:

        Code:
        rc = yajl_copyBuf( 0                      
                         : %addr(jsonRequest)     
                         : JSON_REQUEST_MAX_LENGTH
                         : jsonRequestLength );
        The jsonRequestLength is returning the correct length, but the jsonRequest is missing the 1st two characters: the open curly and the open double-quote. I misread the original response and thought it was missing only the open curly.

        Comment


        • #5

          jsonRequest is a varying length field is it not? In which case you need:
          %addr(jsonRequest: *Data) Or if on an old release
          %addr(jsonRequest + 2)

          Comment


          • #6
            After much "playing around", I think I found the proper "circumvention technique":

            Code:
            dcl-s jsonRequest varchar(65535);   
            dcl-s jsonRequestBuffer char(65535);
            dcl-s jsonRequestLength int(10);     
             // build request in json format                                     yajl_genOpen(*off); // *on = pretty output, *off = condensed output yajl_beginObj();                                                    yajl_addChar('var1':var1);                             yajl_addChar('var2':va2);                                           yajl_endObj();  rc = yajl_copyBuf( 0                                         : %addr(jsonRequestBuffer)                  : %size(jsonRequestBuffer)                  : jsonRequestLength );     jsonRequest = %trim(jsonRequestBuffer);                                                 yajl_genClose();                             http_debug( *ON : debugFileName );                           
            http_setOption('network_ccsid': '1208');                     
            http_xproc( HTTP_POINT_ADDL_HEADER : %paddr(addAuthOnly) );  
            
            monitor;                                                     
              callp http_string( 'POST'                                  
                               : serviceUrl                              
                               : jsonRequest                             
                               : 'application/json' );                   
            on-error;  
             // handle error                                                  
            end-mon;
            Let's hope the way I circumvented this doesn't break something else.


            Comment


            • #7
              This is NOT the way to fix it. It may work - but ... you may also have encountered a compiler bug - I have to check that.

              Look at the prototype definition for http_string - it looks like this:

              Code:
                  D http_string     PR        100000a   varying                                                  
              
                   D   Type                        10a   varying const                                            
              
                   D   URL                      32767a   varying const                                            
              
                   D   SendStr                 100000a   varying const                                            
              
                   D                                     options(*varsize:*omit:*nopass)                          
              
                   D   ContentType              16384A   varying const                                            
              
                   D                                     options(*varsize:*omit:*nopass)
              Note that the third parm is a 100,000 byte varying field. That means it has a _four_ byte header. No _two_ as I said before.

              Let's go back to the very beginning and your first post. As far as I can see, only one simple change was needed in your original code. Either you could have increased the size of jsonRequest to 100,000 bytes OR changed the definition from varying to varying(4) which would have given jsonRequest a four byte header too. However the compiler should have handled that. The other change you needed was to change %size(jsonRequest) to %Len(jsonRequest) - %Size is the number of bytes of storage used by jsonRequest - %Len is the current active length which is what you needed.

              You need to study the prototypes when things don't work as expected.

              Comment


              • #8
                Hey, JonBoy,

                video, sharing, camera phone, video phone, free, upload


                Lol, on a more serious note, thanks for the response. However, it wasn't the http_string() api causing the problem. It was yajl_copybuf(). I don't have authority to edit my posts, otherwise I would have changed it to properly reflect the title. yajl_copybuf() has a pointer variable so I was using jsonRequest varchar(65535) as the definition then when straight into http_string() without thinking about it. I could be wrong, but I think varying parameters can accept other sizes of varying parameters as long as they are not larger than the receiver. I could be wrong but I think that's the rule. That being said, I probably will change jsonRequest to be varchar(100000) so that it'll be compatible with both yajl_copybuf() and http_string().

                Comment


                • #9
                  (...to expose what happened in the process of my discovery..)

                  I created a sample call to the http_string procedure using the definition from QRRPGLESRC/HTTPAPIR4 (we write our code in free format so I modified it to fit our standards). I then needed to store the json request in a variable versus an IFS file (due to a requirement). So I manually typed out the actual json request as a literal and stored it a variable that was varchar(100000). Once I got that working, then I switched to using yajl_copybuf(). I started to experience struggles with the formatting (due to varchar) and couldn't find a sample on the internet that had all of the variable definitions exposed. The closest I could find was where (I think it was Scott) was using the ibm api to directly send a char(100000) back to a browser (as a web service) and that didn't fit my need. At first I thought it was the http_string() api somehow causing the problem with the varying variable. So in the process of _documenting_ my troubles, I changed the variable names definitions for yajl_copybuf() without thinking about feeding them back into http_string(). This is why in the code above you see the jsonRequest definition not matching http_string() but it is a valid parameter for yajl_copybuf().

                  Comment


                  • #10
                    I've read this thread twice, and I can't figure out what you are asking. Or, is it all solved now?

                    Comment


                    • #11
                      Clarifying the continuity of each post would only be possible by giving me edit rights to my posts. (sorry about that). It is resolved.

                      [tldr]
                      The main problem was that I was passing a varying field to yajl_copybuf() and the resulting json had the 1st 2 chars truncated and included the last 2 bytes (string length). I circumvented that by passing in fixed byte character field (not varying), then reassigning the returned json into a varying field. I tried playing with using %size and %len (as I saw in some examples) but that didn't work either. One of the examples I found on the internet defined the json string as 65535 bytes (this is the code I included in the 1st post) and I passed that same string into http_string. At that point I had forgotten to change the json string definition back to varchar(100000) to match the http_string() definition, but I got away with it and jonboy pointed that out. If there is a more elegant solution to call yajl_copybuf() and only use 1 program variable that can then be passed into http_string(), then I'd still like to see it. Otherwise, I found a solution and it's working.
                      [/tldr]

                      Comment


                      • #12
                        The main problem was that I was passing a varying field to yajl_copybuf() and the resulting json had the 1st 2 chars truncated and included the last 2 bytes (string length). I circumvented that by passing in fixed byte character field (not varying), then reassigning the returned json into a varying field. I tried playing with using %size and %len (as I saw in some examples) but that didn't work either.
                        But, Jon told you what you were doing wrong here... under the covers, a VARYING field is really a data structure where the first 2 or 4 bytes (depending on the field size) is an unsigned integer that stores the current length of the string, and the remainder is the data. So if you want to get a pointer to the data portion of the field, you need to use *DATA.

                        So there is no need to use a fixed-length field (yuck). The other thing that's important is that you use the length of the data portion of the field... not %SIZE (which is the length in bytes, and includes the whole thing, not just the data portion)

                        Code:
                        %len(jsonRequest) = %len(jsonRequest:*MAX); 
                          rc = yajl_copyBuf( 0                                            : %addr(jsonRequest:*data)     // pointer to the data                           : %len(jsonRequest:*MAX)       // length of the data portion                  : jsonRequestLength );         %len(jsonRequest) = jsonRequestLength;
                        One of the examples I found on the internet defined the json string as 65535 bytes (this is the code I included in the 1st post) and I passed that same string into http_string. At that point I had forgotten to change the json string definition back to varchar(100000) to match the http_string() definition, but I got away with it and jonboy pointed that out.
                        It shouldn't matter what the size of the field is... as long as it's big enough to fit your whole string. There's no requirement that it be 65535.. that is just an example aimed at something that will work at V5R4 (where that was the max string length) Likewise, http_string() will work fine with any string length, it does not have to be 100k... that is just the maximum size.
                        If there is a more elegant solution to call yajl_copybuf() and only use 1 program variable that can then be passed into http_string(), then I'd still like to see it. Otherwise, I found a solution and it's working.
                        Yep, my example above should work with just jsonRequest.. no need for a 2nd variable.

                        Comment


                        • #13
                          Well... the forum totally hosed the formatting of my code, and I can't edit my posts either, so... here it is again:

                          Code:
                          dcl-s jsonRequest varchar(60000);  // can be any length
                          
                          %len(jsonRequest) = %len(jsonRequest:*MAX);
                          
                          rc = yajl_copyBuf( 0
                                           : %addr(jsonRequest:*data)   // pointer to the data
                                           : %len(jsonRequest:*MAX)     // length of the data portion
                                           : jsonRequestLength );
                          
                          %len(jsonRequest) = jsonRequestLength;

                          Comment


                          • #14
                            Thanks! I modified the code to match your last post.

                            Comment

                            Working...
                            X