Page 1 of 1

JSON - request then decode

PostPosted: Mon Jul 17, 2017 10:19 pm
by TimStone
There was an discussion posted earlier that handled downloading a known JSON file and decoding it. Here is the code that was suggested:

Code: Select all  Expand view

function Main()

   local odoc  := CreateObject( "MSXML2.DOMDocument" )
   local ohttp := CreateObject( "MSXML2.XMLHTTP" )
   local strret

   ohttp:Open( "GET" ,"http://www.w3schools.com/angular/customers.php", .F. )
   ohttp:SetRequestHeader( "Accept"        , "application/xml")
   ohttp:SetRequestHeader( "Content-Type" ,"application/json" )
   oDoc:async := .f.
   oDoc:LoadXml('<?xml version=""1.0"" encoding=""utf-8""?>')
   ohttp:Send(oDoc:xml)
   strret := alltrim(ohttp:responseText)

   ? strret

   StrToHashArray( StrRet )

return nil

function StrToHashArray( cStr )

   local hHash, aHash
   cStr  := CharRepl( "[]", RangeRem( 1, 31, cStr ), "{}" )
   do while '" :' $ cStr
      StrTran( cStr, '" :', '":' )
   enddo
   cStr  := StrTran( cStr, '":', '"=>' )

   hHash := &cStr
   aHash := HGetValueAt( hHash, 1 )
   xbrowser aHash setup ( obrw:autofit(), oBrw:bRClicked := { |r,c,f,o| o:ToDbf( "download.dbf", nil, nil, .t. ) } )
return nil
 


My problem is a bit different. I need to send a request to a defined website, and then read the result.

The sending statement is in the format:
Code: Select all  Expand view

oHttp:=TIpClientHttp():new("https://testserver.com/data/1", .F. )
cJson := '{"partid":"147A964","productDataid":"PR123","locationid":"10000"}'
cRet := ""

IF .NOT. oHttp:open()
   MsgAlert( "Connection error:", oHttp:lastErrorMessage( ) )
ELSE
  oHttp:Post( cJson)
  cRet :=  oHttp:readAll( )
  oHttp:close()
ENDIF

 nFileHandle := FCreate( "retdata.txt" )
 FWrite( nFileHandle, cRet )
 FClose( nFileHandle )
 


And the response should be a JSON string. However, I get no data back. I'll worry about parsing the data when I get a return string, but at this point, it appears JSON may not like the TIP Harbour control. With the example posted on JSON decoding previously, the approach was a bit different. I'd appreciate it if someone has some alternative approaches on how I should be handling this request / response sequence.

Thanks so much.

Tim

For XML data I have been using

Re: JSON - request then decode

PostPosted: Tue Jul 18, 2017 4:47 am
by anserkk
Code: Select all  Expand view
oHttp:= CreateObject("Microsoft.XMLHTTP")
cUrl = "https://testserver.com/data/1"
   
oHttp:Open( "PUT", cUrl, .F.)
oHttp:setRequestHeader( "Content-type", "text/json" )

cJson := {"partid":"147A964","productDataid":"PR123","locationid":"10000"}  
// Try the next line too, I am not sure.
// cJson := '{"partid":"147A964","productDataid":"PR123","locationid":"10000"}'

oHttp:Send(cJson)
   
?  oHttp:Status
? oHttp:StatusText
? oHttp:responseText
   

Re: JSON - request then decode

PostPosted: Tue Jul 18, 2017 3:26 pm
by TimStone
It returns Status 405, StatusText "Method not allowed" and there is no response text.

A web search showed that this will occur if the JSON server does not accept PUT and requires a GET. So I made that change.

Now I get 415 Unsupported media type ....

Tim

Re: JSON - request then decode

PostPosted: Tue Jul 18, 2017 10:22 pm
by TimStone
Based on what the company says, and your method, here is the function code:

Code: Select all  Expand view

FUNCTION ViewCFXServices3(  )

    LOCAL oHttp := CreateObject("Microsoft.XMLHTTP")
    LOCAL cUrl := "https://testserver.com/data/1"
       
    oHttp:Open( "POST", cUrl, .F.)
    ohttp:SetRequestHeader( "Accept", "application/json")
    oHttp:setRequestHeader( "Content-type", "applicationn/json" )

    cJson := '{"partID":"ABC123","productDataId":"CAT001","locationId":"10000"}'
   
    oHttp:Send(cJson)
       
    ? oHttp:Status
    ? oHttp:StatusText
    ? oHttp:responseText

RETURN NIL
 


Using the ARC add in for Google Chrome, the cJson string sent to that server with "application/json" does return the data.

Using this method, the status is 415, the StatusText is "Unsopported Media Type", and there is no responseText

Thoughts from ANYONE on where I go from here ?

Tim

Re: JSON - request then decode

PostPosted: Wed Jul 19, 2017 4:25 am
by anserkk
Please try the following code.

Please note that depending on the documentation from your Web-api service provider, you may have to change the values in the variable cContentType. Depending on the documentation, you may also have to try using GET, PUT, POST methods while opening the URL. For me POST is working fine to send a JSON content to one of my servers and the server is returning me response in JSON format. I believe that it depends on how the Server is configured, not sure. If the server requires authentication, then that too should be dealt with. Provision for Authorization is also there in the sample code that I have provided. I assume that the URL https://testserver.com/data/1 is a dummy. When I tried that URL it is giving me 404 error.

Code: Select all  Expand view
#include "Fivewin.ch"
//----------------------------------//
Function Main()

    LOCAL aHash := hash()
    LOCAL cJson,cContentType:="",cAuthorization:=""
   
    ahash["partID"] = "ABC123"
    ahash["productDataId"] = "CAT001"
    ahash["locationId"] = "10000"

    cJson := hb_jsonEncode(ahash,.f.)
    cContentType:="application/json"
    SendPostToUrl( "https://testserver.com/data/1", cJson, cContentType, cAuthorization  )
Return


//---------------------------------------------------------------------//
Function SendPostToUrl( cUrl, cParams,cContentType,cAuthorization )
    Local oOle,cRet:='',uRet
    default cContentType:="application/x-www-form-urlencoded"
    default cAuthorization:=""
    Try
        oOle := CreateObject( 'MSXML2.XMLHTTP' )
    Catch
        oOle := CreateObject( 'Microsoft.XMLHTTP' )
    End
    oOle:Open( 'POST', cUrl, .f. )
   
    oOle:SetRequestHeader( "Content-Type",cContentType)
    if !empty(cAuthorization)
        oOle:SetRequestHeader( "Authorization",cAuthorization)
    end if
   
    oOle:Send( cParams )
    SysRefresh()
   
    #ifdef __XHARBOUR__
        cRet := oOle:ResponseBody
    #else
        MsgInfo(oOle:ResponseBody)
        cRet:=""
        hb_jsonDecode(oOle:ResponseBody,@cRet)
        xbrowser cRet
    #endif
Return cRet


Regards

Anser

Re: JSON - request then decode

PostPosted: Wed Jul 19, 2017 5:01 am
by TimStone
If you send me your email to tim at gtstone dot com I can send you the actual values to use.

Re: JSON - request then decode

PostPosted: Wed Jul 19, 2017 9:48 am
by Patrizio
TimStone wrote:It returns Status 405, StatusText "Method not allowed" and there is no response text.

A web search showed that this will occur if the JSON server does not accept PUT and requires a GET. So I made that change.

Now I get 415 Unsupported media type ....

Tim


I got the same error with an asynchronous webservice, did you try to put such a cycle between the send and the responsetext?

Code: Select all  Expand view

DO WHILE oXMLHttp:readyState <> 4
SysRefresh()
ENDDO
 

Re: JSON - request then decode

PostPosted: Wed Jul 19, 2017 12:43 pm
by anserkk
TimStone wrote:If you send me your email to tim at gtstone dot com I can send you the actual values to use.

anserkk at gmail.com

I am away from my work computer, may be I can try it out tomorrow.

Re: JSON - request then decode

PostPosted: Wed Jul 19, 2017 7:14 pm
by TimStone
Yes, I did try putting in a delay before looking at the response, but that does not help.

I should note that I building this with FWH 17.06, Harbour, and MSVC++ 2017.

For XML I am using tIPHTTPClient class with no problems, but JSON seems to be unhappy ....

Tim

Re: JSON - request then decode RESOLVED

PostPosted: Wed Jul 19, 2017 8:47 pm
by TimStone
OK ... so after all that, the process is actually quite simple, except when I added an extra n to the word application when stating the header setting for content.

Now I'm successfully implementing the call and receiving the data. I only looked at that for hours and did not see the spelling error.

Tim