Uniface User Forum

 View Only
  • 1.  Uniface REST API

    Posted 08-29-2024 02:39

    Hello,

    We need to implement a REST API that will call a REST WebService of our ERP (JD Edwards).
    Can anyone share a simple REST API Call created with Uniface, so I don't need to perform too many tries and errors before I get it working correctly.

    Thanks,

    Stephane



    ------------------------------
    Stephane Pfefer
    Application Specialist
    Darling
    ------------------------------


  • 2.  RE: Uniface REST API

    Posted 08-29-2024 07:43

    I managed to create this example:

    variables
      handle vUhttp                  ; Handle for UHTTP instance
      struct vMainStruct, vNestedStruct ; Structures for JSON data
      string vProfileName
      string vJsonPayload             ; JSON formatted data
      string vJsonPayload2            ; JSON formatted data
      string vUrl, vMethod            ; REST API URL and method
      string vResponseStatus          ; Status from the HTTP request
      string vHeaders, vContents, vMoreContent      ; Request headers and contents
      string vSendStatus              ; Send status for error checking
    endvariables

    ; REST API Test 
    ; ********** Step 1: Create UHTTP instance and set profile **********
    newinstance "UHTTP", vUhttp  ; Create a new UHTTP instance
    vUhttp->SET_FLAGS(15)
     
    ; ********** Step 2: Define a Nested Structure **********
    ; Create the main structure with nested elements
    vMainStruct = $newstruct
    vMainStruct->name = "John Doe"
    vMainStruct -> email = "john.doe@example.com"
    vMainStruct->Orders = $newstruct
    ; Add a nested structure representing an array of objects
    vNestedStruct = $newstruct
    vNestedStruct->id = 1
    vNestedStruct->item = "Laptop"
    ;vMainStruct->Orders->*{-1} = $newstruct
    ;vMainStruct->Orders->*{-1}->order = vNestedStruct
    vMainStruct->Orders->*{-1} = vNestedStruct
    vNestedStruct = $newstruct
    vNestedStruct->id = 2
    vNestedStruct->item = "Mouse"
    ;vMainStruct->Orders->*{-1} = $newstruct
    ;vMainStruct->Orders->*{-1}->order = vNestedStruct
    vMainStruct->Orders->*{-1} = vNestedStruct

    ; ********** Step 3: Convert Struct to JSON **********
    structToJson vJsonPayload, vMainStruct
    ; Log the JSON payload to verify the structure
    putmess "JSON Payload to send: %%vJsonPayload"
     
    ; ********** Step 4: Send POST Request to Postman Echo **********
    vUrl = "https://postman-echo.com/post"  ; Postman Echo API
    vMethod = "POST"
    vResponseStatus = ""
    ; Initialize headers
    putitem/id vHeaders, "Content-Type", "application/soap+xml; charset=UTF-8"
    putitem/id vheaders, "Accept-Charset", "ISO-8859-1 ; q = 0.4, UTF-16BE; q=0.9"
    vContents = "" ; Initialize contents
    ; Prepare the headers for the POST request
    putitem/id/case vHeaders, "Content-Type", "application/json"  ; Specify JSON format
    ; Send the POST request with the JSON payload
    vUhttp->SEND(vUrl, vMethod, "", "", vHeaders, vJsonPayload, vResponseStatus)
    ; Capture the send status
    vSendStatus = $status
    ; ********** Step 5: Handle and Log Response **********
    if (vSendStatus >= 200 && vSendStatus < 300)
        putmess "Request successful! Response status: %%vSendStatus"
        putmess "Response contents: %%vResponseStatus"
    else
        putmess "Request failed. Status: %%vSendStatus, Response: %%vContents"
    endif

    When I run it, I get this in the log:
    Request successful! Response status: 200
    Response contents: HTTP/1.1 200 OK

    I was expecting to get back the JSON as echo.
    Does anyone while the response contains only "HTTP/1.1 200 OK" ?

    Thanks



    ------------------------------
    Stephane Pfefer
    Application Specialist
    Darling
    ------------------------------



  • 3.  RE: Uniface REST API

    Posted 08-29-2024 10:02

    Hi Stéphane.

    Have you tried to read content after the request ?

    Example in the doc :

    entry uHttpCallOut
    params
      string pUrl         : IN
      string pUsername    : IN
      string pPassword    : IN
      string pHttpHeader  : INOUT
      string pHttpContent : INOUT
    endparams
    variables
      string vMoreContent, vResponse
    endvariables
    
      activate "UHTTP".send(pUrl, "GET", pUsername, pPassword, pHttpHeader, pHttpContent, vResponse)
      while ($status = 1)
        activate "UHTTP".read_Content(vMoreContent)      ; get more data from UHTTP buffer
        pHttpContent = $concat(pHttpContent, vMoreContent)
      endwhile
      if ($status < 0)
        message/error $concat("UHTTP error:%%^", $status)
      else
        message/info $concat("UHTTP success:%%^", $status)  ; 200
      endif
      return 0
    end


    ------------------------------
    Jean-Marc SALIS
    Mp Services
    Montauban Cedex FR
    ------------------------------



  • 4.  RE: Uniface REST API

    Posted 08-30-2024 02:05

    We get the answer in a changed vContent (json in)

    operation GETBYSOSSECNO
    	params
    		string  P_URI       : IN
    		string  P_SIGNUM    : IN
    		string  P_MUNICIPALITY : IN
    		string  P_TOKEN        : IN
    		struct  P_STRUCTASW : OUT
    		numeric P_HTTPSTAT  : OUT
    	endparams
    	variables
    		string  vJson
    		string  vContent, vHeaders, vResponse
    		string  strStatBeg
    		string  vUri
    		handle  vUHTTP
    		struct  vStruct
    	endvariables
    	
    	
    	call MakeJsonSignum(P_SIGNUM, P_MUNICIPALITY, vJson)    ;Define nested struct and convert to Json
    	newinstance "UHTTP", vUHTTP
    	vUHTTP->SET_FLAGS(10)   
    	vURI = P_URI
    	;Create list of headers 
    	putitem/id vHeaders, "Content-Type", "application/json"
    	putitem/id vHeaders, "Authorization", "Bearer %%P_TOKEN%%%" 
    	
    	vContent=vJson
    	; Call the UHTTP.SEND operation
    	P_HTTPSTAT = 0
    	P_HTTPSTAT = vUHTTP->SEND(vURI, "POST", "", "", vHeaders, vContent, vResponse)
    	if(P_HTTPSTAT<0)
    		exit(P_HTTPSTAT)
    	else
    		strStatBeg = "%%P_HTTPSTAT%%%"
    		strStatBeg = strStatBeg[1,1]
    		if(P_HTTPSTAT == 404 | P_HTTPSTAT == 200)
    			jsonToStruct vStruct, vContent
    			P_STRUCTASW = vStruct->result
    			deleteinstance vUHTTP
    		elseif(strStatBeg="1" | strStatBeg="3" | strStatBeg="4" | strStatBeg="5") ;Tex 503 "HTTP/1.1 503 Service Unavailable"
    			exit(P_HTTPSTAT)
    		else
    			jsonToStruct vStruct, vContent
    			P_STRUCTASW = vStruct->result
    			deleteinstance vUHTTP
    			
    		endif
    	endif
    end; operation GETBYSOSSECNO



    ------------------------------
    Roger Wallin
    Abilita Oy
    ------------------------------



  • 5.  RE: Uniface REST API

    Posted 08-30-2024 02:17

    Merci Jean-Marc and Thank you Roger.
    Indeed I completely missed that Content is a INOUT parameter and is changed in the operation.
    Now it works very well.
    Thanks again both of you.



    ------------------------------
    Stephane Pfefer
    Application Specialist
    Darling
    ------------------------------



  • 6.  RE: Uniface REST API

    Posted 09-02-2024 12:18

    Hi Roger
    I just saw that you used "EXIT" in an operation. that's not a good idea

    if(P_HTTPSTAT<0)
    		exit(P_HTTPSTAT)

    This exit kills your instance of the component, all further calls will fail.
    Use RETURN(P_HTTPSTAT) instead :-)
    Ingo



    ------------------------------
    Ingo Stiller
    Aareon Deutschland GmbH
    ------------------------------



  • 7.  RE: Uniface REST API

    Posted 09-03-2024 01:32

    Hi Ingo,
    I suppose that you are right, it would be more efficient  not to "kill" the instance. Actually I was a bit surprised myself as I saw the Exit.
    However what about "all further calls will fail", I suppose using "activate" will just start a new instance of the component.
    Isn't it just about how you want the handle the instance of the component.



    ------------------------------
    Roger Wallin
    Abilita Oy
    ------------------------------



  • 8.  RE: Uniface REST API

    Posted 09-03-2024 03:35

    Hi Ingo,
    It seem that it's not possible to edit a posted message anymore (perhaps that's how it should be). I'll just send another one here.

    I just started to think about this clever code :-) that I posted.
    Isn't it a good solution that as you get a very strange Uniface status  or http status back, that the component is killed and the next call will activate a fresh instance of the component. 



    ------------------------------
    Roger Wallin
    Abilita Oy
    ------------------------------



  • 9.  RE: Uniface REST API

    Posted 09-03-2024 04:10

    Back in the early days, we discovered that if you ran an operation on a particular service, using shared uservers, and someone else ran a long operation which happened to use the same userver, you were in a queue behind them to run your operation again on the same service. 

    Therefore we start (almost) all services activate/stateless, and end (almost) all operations "exit XXX". This way you are never in contention for the same userver with someone else. 

    Future calls to the server will only fail if the previous program used newinstance to start a named instance, and tries to reference that instance by name again. 

    If this is the way you do it Ingo, I am curious how you avoid the contention for uservers and the unintentional delays this causes? 

    Regards, 

    Iain



    ------------------------------
    Iain Sharp
    Head of Technical Services
    Pci Systems Ltd
    Sheffield GB
    ------------------------------



  • 10.  RE: Uniface REST API

    Posted 09-03-2024 05:23

    Hi Roger
    You are right, "ACTIVATE" creates a new instance if none already exists under the name.
    We also have a REST interface and everything is hidden in "real" instances. Even for UHTTP, a separate instance is created via NEWINSTANCE :-)
    Ingo

    here is a detail from the lowest level

    IF($AAK_HND_UHTTP$=="")
        newinstance "UHTTP", $AAK_HND_UHTTP$
        $AAK_HND_UHTTP$->"SET_FLAGS"(8)  ; Send headers with all methods. By default, headers are sent only on the POST and PUT methods.
      ENDIF

      IF($AAK_TOKEN$!="")
        putitem/id/case v_HEADER, "access_token",$AAK_TOKEN$
      ENDIF
      IF(0) putitem/id/case v_HEADER, "Content-Type", "text/xml; charset=UTF-8"
      IF(0)
        IF($USE_JSON$)
          putitem/id/case v_HEADER, "Content-Type", "application/json; charset=UTF-8"

        ELSE
          putitem/id/case v_HEADER, "Content-Type", "application/xml; charset=UTF-8"
        ENDIF
      ENDIF

      v_HEADER_IN   = v_HEADER
      v_CONTENT_OUT = v_CONTENT_IN

      IF(0)
        IF(v_SEC_LVL_U)
          call LP_MELD("HTTP/XML %%v_METHOD%%% '%%v_URL_PART2%%%")
        ELSE
          call LP_MELD("HTTP/XML %%v_METHOD%%% URL=***")
        ENDIF
      ENDIF

      REPEAT
        $AAK_HND_UHTTP$->"READ_CONTENT"($99)
      UNTIL($status!=1)

      $AAK_HND_UHTTP$->"SEND"("%%$AAK_URL_BASE$%%v_URL_PART2%%%",v_METHOD, "", "",v_HEADER, v_CONTENT_OUT, v_STS_RSP)
      v_STS_SND = $status
      WHILE(v_STS_SND == 1 || (v_STS_SND>=200 && v_STS_SND<=299 ) )
        $AAK_HND_UHTTP$->"READ_CONTENT"($99)
        IF($status<0) BREAK
        v_STS_SND = $status
        IF(v_STS_SND!=1 && (v_STS_SND<200 || v_STS_SND>299)  ) BREAK
        v_CONTENT_OUT = $concat(v_CONTENT_OUT,$99)
      ENDWHILE

      IF(0)
        IF(v_SEC_LVL_U)
          call LP_MELD("HTTP/XML %%v_METHOD%%% '%%v_URL_PART2%%%Ä  : STS=%%v_STS_SND%%%/%%v_STS_RSP%%%")
        ELSE
          call LP_MELD("HTTP/XML %%v_METHOD%%% URL=***  : STS=%%v_STS_SND%%%/%%v_STS_RSP%%%")
        ENDIF
      ENDIF

      IF(v_STS_SND<0)
        IF(v_SEC_LVL_U)
          call LP_ERR("UHTTP error %%v_STS_SND%%% : %%v_METHOD%%% '%%v_URL_PART2%%%'")
        ELSE
          call LP_ERR("UHTTP error %%v_STS_SND%%% : %%v_METHOD%%% URL=***")
        ENDIF
        RETURN(v_STS_SND)
      ENDIF

      IF(v_STS_SND==404)
        SELECTCASE $uppercase(v_METHOD)
        CASE "DELETE"
          RETURN(<UIOSERR_OCC_NOT_FOUND>)
        ENDSELECTCASE
        WHILE($scan(" %%"",v_CONTENT_OUT[1:1])>0) v_CONTENT_OUT = v_CONTENT_OUT[2]
        IF($uppercase(v_CONTENT_OUT[1:16])=="RECORD NOT FOUND")
          RETURN(<UIOSERR_OCC_NOT_FOUND>)
        ENDIF
      ELSEIF(v_STS_SND==403) ; 28.11.2018,IST
        RETURN(-9999)
      ENDIF

      IF(v_STS_SND>=400 || v_STS_RSP>=400)
        call LP_DBG_REST_ERR1(v_METHOD,v_URL_PART2,v_STS_SND,v_HEADER_IN,v_CONTENT_IN,v_STS_RSP,v_HEADER,v_CONTENT_OUT,v_SEC_LVL)
        RETURN($status)
      ENDIF

      IF(0) ; DBG
        call LP_DBG_REST_ERR1(v_METHOD,v_URL_PART2,v_STS_SND,v_HEADER_IN,v_CONTENT_IN,v_STS_RSP,v_HEADER,v_CONTENT_OUT,v_SEC_LVL)
      ENDIF

      RETURN(v_STS_RSP)



    ------------------------------
    Ingo Stiller
    Aareon Deutschland GmbH
    ------------------------------