Web API Wizard- receiving multiple requests in one structure

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
Joerg Hamacher
Posts: 109
Joined: Thu Feb 11, 2016 12:01 am

Web API Wizard- receiving multiple requests in one structure

Post by Joerg Hamacher » Fri Jul 22, 2022 10:45 pm

Hello everybody,

I need to create an Web API that should receive the following structure:
struktur.gif
struktur.gif (6.72 KiB) Viewed 10116 times
How many such elements the request contains can vary from time to time.

How many such elements the request contains can vary from time to time.
I have in my Web API server module, which I created automatically using the LANSA wizard, a path /customer_price, which in turn has an operation Getcustomer_prices (verb=get).

Do I have to define anything in this operation to receive this structure? By default the parameter SearchString is created automatically.
And how do I process such a structure in the associated server routine Getcustomer_prices?

Unfortunately I can't find any hint in the documentation or LearnLANSA tutorials on how to implement this - and I have no idea how to handle this...

Many thanks in advance for your support,
Jörg

Catt
Posts: 6
Joined: Mon Jun 10, 2019 8:00 pm

Re: Web API Wizard- receiving multiple requests in one structure

Post by Catt » Sat Jul 23, 2022 12:56 am

You might struggle using the verb get because I think it doesn't allow for a request body. I think the wizard generates most of the RDMLX for the routine. The request also needs to be defined in the Path/Operations section within the request tab.

Catt
Posts: 6
Joined: Mon Jun 10, 2019 8:00 pm

Re: Web API Wizard- receiving multiple requests in one structure

Post by Catt » Sat Jul 23, 2022 1:07 am

Further, if adding a request in after the wizard has done it's work you'll need to put in a Define_Com Class(#Com_Home.xxRequestTypeName) statement at the top of the server routine. xxRequestTypeName just being replaced by the name of your request as defined in Types. Then further down once in the If (#Operation.TryBind( #Context )) section of code a line needs to be added to use that defined component. This will be : Get Com(#Operation.Request.ContentJson) Com_Fields(#xxRequestTypeName).

User avatar
Dino
Posts: 435
Joined: Fri Jul 19, 2019 7:49 am
Location: Robbinsville, NC
Contact:

Re: Web API Wizard- receiving multiple requests in one structure

Post by Dino » Tue Jul 26, 2022 9:27 am

Hi,

Let's try to do this together...

for simplicity (because you can also just go to schema and manually define it), I created first a simple table, called it cnrtable, with fields cnr, snr, sku and amount then a new server module from zero, and drag that table in Schema, which creates a cnrtableArray and a cnrtableObject.

Then create a couple of server routines, one to handle the status, and one to handle the getPricesOperation.

Went to the API definition tab, and filled all the marked things here with the exception of the Schema types which were the result of just draggin the table in the schema area... notice I need to use Post instead of Get (my first error when trying this) and be sure to fill the Identifier when needed:
receivingjson01.png
receivingjson01.png (42.76 KiB) Viewed 10082 times
then added this server routine, pretty basic first, to see if I can receive the array:

Code: Select all

Begin_Com Role(*EXTENDS #PRIM_SRVM)
Srvroutine Name(cnrRoutine) Response(*HTTP #http)
* Instance of the getPricesOperation. this #COM_Home.Status relates to API Definition, Operation Name
Define_Com Class(#Com_Home.getPricesOperation) Name(#Operation)
Define Field(#contentstring) Type(*Char) Length(256) Decimals(0)

Define_Com Class(#Com_Home.cnrtableArray) Name(#cnrtableArray)
Define_Com Class(#Com_Home.cnrtableObject) Name(#cnrtableObject)

If (#Operation.TryBind( #http ))
#std_strng := #Operation.Request.ContentJson.ToJsonString.AsNativeString

#contentstring := '{' + (10).AsUnicodeString + '"JobID": "' + *JOBNBR + '",' + (10).AsUnicodeString + '"ServerStatus": "OK",' + (10).AsUnicodeString + '"Count": "' + #std_strng + '}'
#Operation.Response.SetContentString( #contentstring )
Endif
Endroutine
Srvroutine Name(statusRoutine) Response(*HTTP #http)
endroutine
End_Com
then went to postman, created an small json to test:

Code: Select all

[{"cnr": 123456,
"snr": "00",
"sku": "1531058",
"amount": 12},
{"cnr": 123456,
"snr": "00",
"sku": "1531058",
"amount": 11},
{"cnr": 123456,
"snr": "00",
"sku": "1531058",
"amount": 10}]
and yes I am receiving the array as you can see in the string I return as response.

Next post... processing each item of the array and return the total of the amount or maybe just another array with the prices
receivingjson02.png
receivingjson02.png (65.17 KiB) Viewed 10082 times
Last edited by Dino on Wed Jul 27, 2022 12:38 am, edited 1 time in total.

User avatar
Dino
Posts: 435
Joined: Fri Jul 19, 2019 7:49 am
Location: Robbinsville, NC
Contact:

Re: Web API Wizard- receiving multiple requests in one structure

Post by Dino » Tue Jul 26, 2022 11:36 am

Server routine changed to read the array and return the total of the amounts:

Code: Select all

Srvroutine Name(cnrRoutine) Response(*HTTP #http)
* Instance of the Status Operation.. this #COM_Home.Status relates to API Definition, Operation Name
Define_Com Class(#Com_Home.getPricesOperation) Name(#Operation)
Define Field(#contentstring) Reffld(#VF_ELTXTX)

Define_Com Class(#XPRIM_RandomAccessJsonReader) Name(#Reader) Reference(*Deferred)
Define_Com Class(#XPRIM_ErrorInfo) Name(#ErrorObject) Reference(*Deferred)
Define_Com Class(#PRIM_BOLN) Name(#Found)

If (#Operation.TryBind( #http ))
#VF_ELTXTX := #Operation.Request.ContentJson.ToJsonString.AsNativeString

#Reader.SetSourceString String(#VF_ELTXTX) ErrorInfo(#ErrorObject)

#Reader.BeginArrayWithPath Path('/') Found(#Found)

#std_amnt := 0
Begin_Loop Using(#STD_NUM) To(#Reader.GetChildCount)
#Reader.BeginObjectAtIndex Index(#STD_NUM) Found(#Found)
If (#Found)
#cnr := #Reader.ReadNumberWithName( 'cnr' )
#snr := #Reader.ReadStringWithName( 'snr' ).AsNativeString
#sku := #Reader.ReadStringWithName( 'sku' ).AsNativeString
#amount := #Reader.ReadNumberWithName( 'amount' )

#std_amnt += #amount

#Reader.EndObject
Endif
End_Loop
#Reader.EndArray

#std_strng := #std_count.AsString

#contentstring := '{' + (10).AsUnicodeString + '"JobID": "' + *JOBNBR + '",' + (10).AsUnicodeString + '"ServerStatus": "OK",' + (10).AsUnicodeString + '"Count": "' + #Reader.GetChildCount.AsString + '",' + (10).AsUnicodeString + '"Total Amount":' + #std_amnt.AsString + (10).AsUnicodeString + '}'
#Operation.Response.SetContentString( #contentstring )
Endif
Endroutine
result is:

Code: Select all

{
"JobID": "013016",
"ServerStatus": "OK",
"Count": "3",
"Total Amount":33.00
}
now if you want to return a json instead of a string, it's time to change the api definition, adding another schema with more fields to respond (or even reuse the same one and expand it), and probably a fetch inside this begin_loop to start preparing the response with basically fetch and add_entry following the same steps as the typical server module that responds with the list of all records, converting the list in an array.

Joerg Hamacher
Posts: 109
Joined: Thu Feb 11, 2016 12:01 am

Re: Web API Wizard- receiving multiple requests in one structure

Post by Joerg Hamacher » Tue Jul 26, 2022 6:51 pm

Hi Dino, hi Catt,

thank you very much for your help!
This is a great description! Now I understand the interaction of the individual parts.
I now also got it working with the array response.

:D

Best regards,
Jörg

User avatar
Dino
Posts: 435
Joined: Fri Jul 19, 2019 7:49 am
Location: Robbinsville, NC
Contact:

Re: Web API Wizard- receiving multiple requests in one structure

Post by Dino » Sat Jun 01, 2024 2:13 am

Hi guys

While the code in this post still works, I would have thought that something like other code should work instead today but I cannot make it work... I guess I am missing something here.

Code: Select all

Define_Com Class(#Com_Home.cnrtableArray) Name(#cnrtableArray)
...
Get Com(#Operation.Request.ContentJson.cnrtableArray) Com_Fields(#cnrtableArray)
...
selectlist #cnrtableArray
...
endselect

User avatar
MARCOREMMEDATA
Posts: 8
Joined: Mon Apr 11, 2022 4:48 pm
Location: ITALIA
Contact:

Re: Web API Wizard- receiving multiple requests in one structure

Post by MARCOREMMEDATA » Fri Sep 27, 2024 11:34 pm

Thank you for this article, it solved a problem for me. I share the solution to access an array within an array element

This is the Json

Code: Select all

[
	{
		"cnr": 123456,
		"snr": "00",
		"sku": "1531058",
		"amount": 12,
		"tag": [
			{
				"a1": 5,
				"a2": 7
			}
		]
	},
	{
		"cnr": 123456,
		"snr": "00",
		"sku": "1531058",
		"amount": 11,
		"tag": [
			{
				"a1": 3,
				"a2": 4
			}
		]
	},
	{
		"cnr": 123456,
		"snr": "00",
		"sku": "1531058",
		"amount": 10,
		"tag": [
			{
				"a1": 6,
				"a2": 7
			}
		]
	}
]

this the source

Code: Select all

DEFINE_COM CLASS(£XPRIM_RandomAccessJsonReader) NAME(£Reader)
DEFINE_COM CLASS(£XPRIM_ErrorInfo) NAME(£Error)

DEFINE_COM CLASS(£PRIM_BOLN) NAME(£Found)

DEFINE FIELD(£cnr) TYPE(*DEC) LENGTH(10) DECIMALS(3)
DEFINE FIELD(£SNR) TYPE(*CHAR) LENGTH(20)
DEFINE FIELD(£sku) TYPE(*CHAR) LENGTH(20)
DEFINE FIELD(£amount) TYPE(*DEC) LENGTH(10) DECIMALS(3)

DEFINE FIELD(£a1) TYPE(*DEC) LENGTH(1) DECIMALS(0)
DEFINE FIELD(£a2) TYPE(*DEC) LENGTH(1) DECIMALS(0)

DEFINE FIELD(£cnt1) TYPE(*DEC) LENGTH(5) DECIMALS(0)
DEFINE FIELD(£cnt2) TYPE(*DEC) LENGTH(5) DECIMALS(0)

DEFINE FIELD(£id1) TYPE(*DEC) LENGTH(5) DECIMALS(0)
DEFINE FIELD(£id2) TYPE(*DEC) LENGTH(5) DECIMALS(0)

£Reader.SetSourceString STRING('[{"cnr":123,"snr":"AA","sku":"SKU_1","amount":12,"tag":[{"a1":1,"a2":2},{"a1":3,"a2":4}]},{"cnr":456,"snr":"BB","sku":"SKU_2","amount":11,"tag":[{"a1":5,"a2":6}]},{"cnr":789,"snr":"CC","sku":"SKU_3","amount":10,"tag":[{"a1":7,"a2":8}]}]') ERRORINFO(£Error)

£Reader.BeginArrayWithPath PATH('/') FOUND(£Found)

£std_amnt := 0
£cnt1 := £Reader.GetChildCount

BEGIN_LOOP USING(£id1) TO(£cnt1)
£Reader.BeginObjectAtIndex INDEX(£id1) FOUND(£Found)
IF (£Found)
£cnr := £Reader.ReadNumberWithName( 'cnr' )
£snr := £Reader.ReadStringWithName( 'snr' ).AsNativeString
£sku := £Reader.ReadStringWithName( 'sku' ).AsNativeString
£amount := £Reader.ReadNumberWithName( 'amount' )

£Reader.BeginArrayWithPath PATH("/tag") FOUND(£Found)
IF (£Found)

£cnt2 := £Reader.GetChildCount

BEGIN_LOOP USING(£id2) TO(£cnt2)

£Reader.BeginObjectAtIndex INDEX(£id2) FOUND(£Found)
IF (£Found)

£a1 := £Reader.ReadNumberWithName( 'a1' )
£a2 := £Reader.ReadNumberWithName( 'a2' )

£Reader.EndObject
ENDIF

END_LOOP

£Reader.EndArray

ENDIF

£std_amnt += £amount

£Reader.EndObject
ENDIF
END_LOOP

£Reader.EndArray
MARCO ROSSI | Software Developer Sr. - Software Production

Post Reply