How to get response from Integrator HTTP POST

This Q&A forum allows users to post and respond to "How Do I Do ....." questions. Please do not use to report (suspected) errors - you must use your regional help desk for this. The information contained in this forum has not been validated by LANSA and, as such, LANSA cannot guarantee the accuracy of the information.
Post Reply
jyoung
Posts: 656
Joined: Thu Jan 21, 2016 6:43 am
Location: Oklahoma City, OK USA

How to get response from Integrator HTTP POST

Post by jyoung » Wed Mar 23, 2016 9:08 am

I am trying to make a HTTP POST request with Integrator and I need to get the response back.

The POST is a name value pair and the response is plain text. So I am using the HttpService OutboundNameValue handler. When I am debugging, after I make the call to the JSM command, I can see the response has been received (by JSMXSTS and JSMXMSG), but I cannot get to it.

The documentation for the OutboundNameValue handler does not mention anything about getting the response back, so I assume I have to use another handler to get it.

I have tried to use the InboundText handler but then I get an error saying "InboundTextHandler: no field list" which from the documentation there should not be any field list. When I try to use a list I get an error saying "Recieve to list is not supported".

Code: Select all

* ====================================================
*  Process ........:  DSTCPS
*  Function .......:  DSTC001
*  Created on .....:  16/03/22  at  13:45:07
*  Template........:  JSMXSKEL
*  Inputs..........:  wk_TCCustId, wk_TCPassword, wk_TCAction, wk_TCReturnUrl
*  Outputs.........:  wk_TCTransactionId
* ====================================================

function options(*DIRECT)

* WORKING FIELDS
* ====================================================
def_list name(#Content) fields(#STD_TEXT #STD_TEXTL) type(*WORKING) entrys(*MAX)
def_list name(#Response) fields(#STD_TEXT #wk_TCTransactionId) type(*WORKING) entrys(*MAX)

* setup our content list, this will be used as the content for in the request
#STD_TEXT := "custid"
#STD_TEXTL := #wk_TCCustId
add_entry to_list(#Content)

#STD_TEXT := "password"
#STD_TEXTL := #wk_TCPassword
add_entry to_list(#Content)

#STD_TEXT := "action"
#STD_TEXTL := #wk_TCAction
add_entry to_list(#Content)

#STD_TEXT := "returnurl"
#STD_TEXTL := #wk_TCReturnUrl
add_entry to_list(#Content)

*  OPEN JSM AND VERIFY STATUS
use builtin(JSMX_OPEN) to_get(#JSMXSTS #JSMXMSG #JSMXHDLE1)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* BUILD THE SERVICE LOAD COMMAND
#JSMXCMD := 'SERVICE_LOAD'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE' 'HTTPSERVICE')
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* SEND THE REQUEST
#JSMXCMD := 'SEND'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'OutboundNameValue')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'URI' '/api/token.php')  /* not actual URI */
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HOST' 'sub.domain.com') /* not actual HOST */
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SECURE' '*YES')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'METHOD' 'POST')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'WAIT' '*YES') 
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TIMEOUT' '10000')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE_LIST' 'STD_TEXT, STD_TEXTL')

clr_list named(#Response)

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)

* RECEIVE THE RESPONSE
#JSMXCMD := 'RECEIVE'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'InboundText')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TO' 'wk_TCTransactionID')
* execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE_LIST' 'STD_TEXT, #wk_TCTransactionId')

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)

* exchange the transaction id back to the caller ??? do I need to do this ???
* exchange fields(#wk_TCTransactionId)

* UNLOAD SERVICE
#JSMXCMD := 'SERVICE_UNLOAD'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* CLOSE JSM AND VERIFY STATUS
use builtin(JSMX_CLOSE) with_args(#JSMXHDLE1) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

return

* Subroutine to build JSM commands. existing JSM command
*
subroutine name(KEYWRD) parms((#W_CMDX *BOTH) (#W_KEYWRD *RECEIVED) (#W_KEYVAL *RECEIVED))
define field(#W_CMDX) reffld(#JSMXCMD)
define field(#W_KEYWRD) reffld(#STD_TEXT)
define field(#W_KEYVAL) reffld(#STD_TEXTL)
#W_CMDX += ' ' + #W_KEYWRD + '(' + #W_KEYVAL + ')'
endroutine

*  Check the status of the JSM command issued
*
subroutine name(CHECK_STS) parms(#W_HDLE)
define field(#MSGDTA) type(*CHAR) length(132)
define field(#W_HDLE) type(*CHAR) length(4)

if cond('#JSMXSTS *NE OK')
#MSGDTA := 'Error Status Code: ' + #JSMXSTS
message msgid(DCM9899) msgf(DC@M01) msgdta(#MSGDTA)
#MSGDTA := 'Error Message: ' + #JSMXMSG
message msgid(DCM9899) msgf(DC@M01) msgdta(#MSGDTA)
endif
endroutine

LANSAGuru
Posts: 68
Joined: Thu Mar 24, 2016 5:31 am

Re: How to get response from Integrator HTTP POST

Post by LANSAGuru » Thu Mar 24, 2016 6:00 am

1) The send is wrong. Missing the list of name value pairs (#content)

should be
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #content)

2) When debugging Integrator always do this

#JSMCMD := 'SERVICE_LOAD SERVICE(HTTPService) SERVICE_CONTENT(*HTTP) TRACE(*YES)'

This will produce trace files in '/LANSA_xxxpgmlib/jsm/instance/trace/clientnnnnnn/
Each service load produces a new client folder.
Debugging Integrator problems would require the entire folder contents zipped up.

3) I don't use the KEYWRD subroutine to build commands. You can accomplish the same by coding this directly and simply using the concat operator in 1 step. My opinion is this makes the code more concise and easier to read. This opinion my vary from developer to developer

4) This code has worked for me

* this works
#JSMXCMD := 'RECEIVE HANDLER(InboundText) TO(STD_TEXTL)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)

* your code
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'InboundText')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TO' 'wk_TCTransactionID')
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)

I suspect that you are not actually sending any name,value pairs so are not getting a response (it is blank).

The other thing that looks suspicious is the long field name. There was an issue where long field names (>10) were not mapping properly in some cases. So this is another possibility.

jyoung
Posts: 656
Joined: Thu Jan 21, 2016 6:43 am
Location: Oklahoma City, OK USA

Re: How to get response from Integrator HTTP POST

Post by jyoung » Thu Mar 24, 2016 6:55 am

Thanks for pointing out the trace stuff. I got the send to give me back a response, when I look at the trace files, I have a HTTP_RESPONSE_CONTENT.html that has the response, in this a transaction id.

I am still getting an error on the receive though. Here is a chunk of the service trace log.

Code: Select all

Create trace file : HTTP_RESPONSE_CONTENT.HTML
Create trace file : HTTP_RESPONSE_PROTOCOL.TXT
Command    : OK "HTTP response has been received"
--------------------------------------------------

--------------------------------------------------
Process    : *COMPONENT
Function   : DSTC001
Partition  : SYS
Job Name   : JOB009128
Job User   : USERID
Job Number : 009128
Command    : RECEIVE HANDLER(InboundText) TO(STD_TEXTL)
Receive content handler : com.lansa.jsm.service.InboundTextHandler
Using inbound content handler type 2
InboundTextHandler receive method has been invoked
Received content type : text/html
Use inbound encoding : Cp1252

stack trace: java.lang.IllegalArgumentException: InboundTextHandler: no field list
	at com.lansa.jsm.service.InboundTextHandler.byte(Unknown Source)
	at com.lansa.jsm.service.InboundTextHandler.receive(Unknown Source)
	at com.lansa.jsm.service.HTTPService.if(Unknown Source)
	at com.lansa.jsm.service.HTTPService.char(Unknown Source)
	at com.lansa.jsm.service.HTTPService.command(Unknown Source)
	at com.lansa.jsm.f.for(Unknown Source)
	at com.lansa.jsm.f.do(Unknown Source)
	at com.lansa.jsm.f.run(Unknown Source)

Command    : ERROR "InboundTextHandler: no field list"
--------------------------------------------------

--------------------------------------------------
Process    : *COMPONENT
Function   : DSTC001
Partition  : SYS
Job Name   : JOB009128
Job User   : USERID
Job Number : 009128
Command    : SERVICE_UNLOAD
Command    : OK "Service successfully unloaded"
--------------------------------------------------

=================== TRACE CLOSE ==================
You mention in "4" using STD_TEXTL, I've tried that and I still get the aforementioned error.

I've tried passing just STD_TEXTL to the receive command and I get an error saying that it does not produce a LANSA list. Adding STD_TEXTL to a list and passing that to to_get results in the aforementioned error as well.

LANSAGuru
Posts: 68
Joined: Thu Mar 24, 2016 5:31 am

Re: How to get response from Integrator HTTP POST

Post by LANSAGuru » Thu Mar 24, 2016 7:09 am

Please zip up the entire CLIENT folder trace and upload it here. I will take a look.

jyoung
Posts: 656
Joined: Thu Jan 21, 2016 6:43 am
Location: Oklahoma City, OK USA

Re: How to get response from Integrator HTTP POST

Post by jyoung » Thu Mar 24, 2016 8:06 am

Attached are the trace files. I had to sanitize the HTTP_CONTENT and SERVICE files as they have ids and passwords to the remote service.

This is the latest version of the code.

Code: Select all

* ====================================================
*  Process ........:  DSTCPS
*  Function .......:  DSTC001
*  Created on .....:  16/03/22  at  13:45:07
*  Description ....:  Trust Commerce Get Transaction ID
*  Template........:  JSMXSKEL
*  Inputs..........:  wk_TCCustId, wk_TCPassword, wk_TCAction, wk_TCReturnUrl
*  Outputs.........:  wk_TCTransactionId
* ====================================================

function options(*DIRECT)

* WORKING FIELDS
* ====================================================
def_list name(#Content) fields(#STD_TEXT #STD_TEXTL) type(*WORKING) entrys(*MAX)
def_list name(#Response) fields(#STD_TEXTL) type(*WORKING) entrys(*MAX)

* setup our content list, this will be used as the content for in the request
#STD_TEXT := "custid"
#STD_TEXTL := #wk_TCCustId
add_entry to_list(#Content)

#STD_TEXT := "password"
#STD_TEXTL := #wk_TCPassword
add_entry to_list(#Content)

#STD_TEXT := "action"
#STD_TEXTL := #wk_TCAction
add_entry to_list(#Content)

#STD_TEXT := "returnurl"
#STD_TEXTL := #wk_TCReturnUrl
add_entry to_list(#Content)

* ????? do I need to add an entry ?????
#STD_TEXTL := ""
add_entry to_list(#Response)

*  OPEN JSM AND VERIFY STATUS
use builtin(JSMX_OPEN) to_get(#JSMXSTS #JSMXMSG #JSMXHDLE1)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* BUILD THE SERVICE LOAD COMMAND
#JSMXCMD := 'SERVICE_LOAD'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE' 'HTTPSERVICE')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE_CONTENT' '*HTTP')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TRACE' '*YES')
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* SEND THE REQUEST
#JSMXCMD := 'SEND'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'OutboundNameValue')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'URI' '/trusteeapi/token.php')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HOST' 'vault.trustcommerce.com')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SECURE' '*YES')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'METHOD' 'POST')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'WAIT' '*YES')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TIMEOUT' '10000')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE_LIST' 'STD_TEXT, STD_TEXTL')

* clr_list named(#Response)

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #Content)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)

* RECEIVE THE RESPONSE
#JSMXCMD := 'RECEIVE'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'InboundText')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TO' 'STD_TEXTL')

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #Response)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)

* exchange the transaction id back to the caller ??? do I need to do this ???
* exchange fields(#wk_TCTransactionId)

* UNLOAD SERVICE
#JSMXCMD := 'SERVICE_UNLOAD'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

* CLOSE JSM AND VERIFY STATUS
use builtin(JSMX_CLOSE) with_args(#JSMXHDLE1) to_get(#JSMXSTS #JSMXMSG)
execute subroutine(CHECK_STS) with_parms(#JSMXHDLE1)

return

* Subroutine to build JSM commands. existing JSM command
*
subroutine name(KEYWRD) parms((#W_CMDX *BOTH) (#W_KEYWRD *RECEIVED) (#W_KEYVAL *RECEIVED))
define field(#W_CMDX) reffld(#JSMXCMD)
define field(#W_KEYWRD) reffld(#STD_TEXT)
define field(#W_KEYVAL) reffld(#STD_TEXTL)
#W_CMDX += ' ' + #W_KEYWRD + '(' + #W_KEYVAL + ')'
endroutine

*  Check the status of the JSM command issued
*
subroutine name(CHECK_STS) parms(#W_HDLE)
define field(#MSGDTA) type(*CHAR) length(132)
define field(#W_HDLE) type(*CHAR) length(4)

if cond('#JSMXSTS *NE OK')
#MSGDTA := 'Error Status Code: ' + #JSMXSTS
message msgid(DCM9899) msgf(DC@M01) msgdta(#MSGDTA)
#MSGDTA := 'Error Message: ' + #JSMXMSG
message msgid(DCM9899) msgf(DC@M01) msgdta(#MSGDTA)
endif
endroutine
Attachments
Trace.zip
(3.65 KiB) Downloaded 117 times

jyoung
Posts: 656
Joined: Thu Jan 21, 2016 6:43 am
Location: Oklahoma City, OK USA

Re: How to get response from Integrator HTTP POST

Post by jyoung » Thu Mar 24, 2016 9:15 am

I think I figured it out. :D

I kept reading http://docs.lansa.com/140/EN/LANSA015/# ... ommand.htm and was really hung up on the 3rd optional argument about the field definitions.

I added the response list to the receive command with_args and it worked!

So my lists are defined like this

Code: Select all

* WORKING FIELDS
* ====================================================
def_list name(#Content) fields(#STD_TEXT #STD_TEXTL) type(*WORKING) entrys(*MAX)
def_list name(#Response) fields(#STD_TEXTL) type(*WORKING) entrys(*MAX)
The the request / response

Code: Select all

* SEND THE REQUEST
#JSMXCMD := 'SEND'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'OutboundNameValue')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'URI' '/trusteeapi/token.php')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HOST' 'vault.trustcommerce.com')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SECURE' '*YES')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'METHOD' 'POST')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'WAIT' '*YES')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TIMEOUT' '10000')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'SERVICE_LIST' 'STD_TEXT, STD_TEXTL')

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #Content)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)

* RECEIVE THE RESPONSE
#JSMXCMD := 'RECEIVE'
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'HANDLER' 'InboundText')
execute subroutine(KEYWRD) with_parms(#JSMXCMD 'TO' 'STD_TEXTL')

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD #Response) to_get(#JSMXSTS #JSMXMSG #Response)
execute subroutine(CHECK_STS) with_parms(#JSMXCMD)
This line was the solution

Code: Select all

use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD #Response) to_get(#JSMXSTS #JSMXMSG #Response)
None of the examples or tutorials seem to show this, so I don't know if this is new to V14.

LANSAGuru
Posts: 68
Joined: Thu Mar 24, 2016 5:31 am

Re: How to get response from Integrator HTTP POST

Post by LANSAGuru » Fri Mar 25, 2016 1:55 am

There are two ways to get data to be mapped between the JSM subsystem and your job (via socket).
First way is via a list with field definitions as you saw.

def_list name(#Response) fields(#STD_TEXTL) type(*WORKING) entrys(*MAX)
#jsmxcmd := '<command> service_list(STD_TEXTL)'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #RESPONSE)

This method is required if you are actually passing a list or receiving a list of data.

The second way does not require the creation of a dummy list. Use the SERVICE_EXCHANGE keyword.

#jsmxcmd := '<command> SERVICE_EXCHANGE(*FIELD)'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE1 #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)

jyoung
Posts: 656
Joined: Thu Jan 21, 2016 6:43 am
Location: Oklahoma City, OK USA

Re: How to get response from Integrator HTTP POST

Post by jyoung » Fri Mar 25, 2016 3:03 am

Ok, so I added the SERVICE_EXCHANGE to the response and it worked.

Thank you so much for your patience and help.

One last question, how do you know this? I don't know if I am not looking at the right documentation or just not understanding what it is telling me. Being new to LANSA I am struggling with finding the information.

LANSAGuru
Posts: 68
Joined: Thu Mar 24, 2016 5:31 am

Re: How to get response from Integrator HTTP POST

Post by LANSAGuru » Fri Mar 25, 2016 7:14 am

This one is in the documentation.

http://docs.lansa.com/140/en/lansa093/i ... e_exchange

There are some examples in the appendix of the Integrator guide that use this specific keyword.

http://docs.lansa.com/140/en/lansa093/i ... J_0001.htm

I learned in the beginning by going through the samples in the appendix and experimentation. Anything I could not figure out, I asked LANSA support. The Integrator guide is my primary resource for Integrator programming. Once I got used to how it is laid out and what to look for it started making more sense. Gratefully the Integrator tracing is very detailed, so this makes figuring out problems much easier. It is like a flight recorder for a transaction.

There is this rather old tutorial I originally used for SOAP, but it was really detailed which was nice.
http://www.lansa.com/support/tips/t0382.htm
I originally started doing SOAP in LANSA by starting here.

As with most of the LANSA documentation, it is a reference, and not a step by step guide.

This forum is rather new, so hopefully we will see some cross pollination of sample code. Every example, tutorial, or mini example is welcomed. Historically you have not seen a lot of postings on LANSA on the web except in the LANSA Yahoo Group. I suspect that most people go through support if they have a question.

On my todo list...post examples in the tips and techniques section. I have a huge library of STUFF I have saved over the years, but much of it might not even be relevant today. Hopefully I can get some stuff cleaned up and posted out here. Have to make sure it all still works. :-)

Post Reply