Hi Ray,
In v10, the apim module is what I call the "v5 compatibility" module. The v10 API Gateway context is different than v5 and also has the data in a particular data type (in this case a string), and the apim module's getvariable function will attempt to return to you a response like v5 would, which for a *.body would attempt to return a parsed JSON object if the content type was a JSON type. The error would indicate that your request Content-Type header was application/json; charset=UTF-8
which obviously doesn't match the content type of the data that the client is providing. The request Content-Type header should be application/x-www-form-urlencoded
. Two options here:
1. Have your client provide the proper content-type request header to match the data type of the payload being sent. In this case a payload should be returned from the compatibility module getvariable function, but depending upon the APIC release you are using, it may be a string (which was not how v5 would have returned it) or it will be in a "XML Binary Node" (a recent fix to the compatibility module to return what v5 would have returned for a non-XML / non-JSON payload. To convert a binary node to a string and make your code safe regardless of the APIC version you're using, you can use the following:
// is the return from apim.getvariable a binary node, convert it to a string
if ((body.item && body.length > 0 && body.item(0).nodeType === 13)) {
body = body.item(0).toBuffer().toString();
}
2. Change the GatewayScript to use the native context.get('request.body')
or context.request.body.readAsBuffer(function(error, buffer) {});
The latter like many GatewayScript functions has an asynchronous callback function which would receive the data in the buffer variable where you could convert that buffer to a string and then pass it to a function that would continue execution from within the callback.
Note, in either case, by default, the API Gateway Service streams the request payload which means that the processing of the assembly will start in parallel with the consuming of the request.body, so in your GatewayScript, the request.body may not be available. To force it to be available, especially with a payload so small where streaming isn't going to provide a tangible performance benefit, you can either a) set the x-ibm-configuration.buffering: true
option in your API b) you can provide as your first policy in the assembly a "parse" policy. Given your content type request header isn't correct, don't use the "Use Content Type" in the parse policy, so the policy will inspect the payload to see the string can't be JSON or XML and will simply read in all of the data before continuing.
Hope this helps!
Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
------------------------------
Original Message:
Sent: Tue May 10, 2022 01:25 PM
From: Ray Jennings
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
Steve, Thank you for your reply. I am trying to copy the "request.body" to "message.body" (which is just a string: "username=xxx&password=yyy")
But I am getting an error of: (as shown in dpod)
Failed to parse 'request.body' as content type 'application/json;charset=UTF-8'.
My initial API Gateway script to test this is:
var apim=require('apim');
apim.setvariable('message.headers.Content-Type', 'application/x-www-form-urlencoded');
var body = apim.getvariable('request.body'); # Failure is here
var str_body = body.toString();
apim.setvariable('message.body', str_body);
------------------------------
Ray Jennings
Original Message:
Sent: Fri April 29, 2022 05:44 PM
From: Steve Linn
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
Hi Ray,
The original question in this thread was how to send a urlencoded message to a backend. As I noted earlier in this thread, you can build a simple string in the form
p1=value1&p2=test%24%24test
by building your string and then using the encodeURIComponent() function to properly encode the appropriate characters requiring encoding. Set that string into message.body, set the content type to application/x-www-form-urlencoded in your gateway script. The subsequent invoke policy will send that to your backend .
If your question is will the gateway accept a request of this type, I believe you can do this with both v5 and v10. In v5 request.body should be the inbound form string which invoke should be able to consume. If you have created a message.body in your API via some previous policy, invoke only uses message.body so you may need to copy request.body to message.body via some gateway script. Perhaps your issue is with the APIM test tool not sending this request properly? If you can provide some more detail of what you're encountering that would be helpful.
Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Fri April 29, 2022 12:08 PM
From: Ray Jennings
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
Is there a way in the API Manager to allow a x-www-form-urlencoded?
1) I do not want to force my users to change from x-www-form-urlencoded to json
2) I want to be able to test this in the APIM Assembly (sandbox) but there is no way to add a generic body even if not required is not checked.
------------------------------
Ray Jennings
Original Message:
Sent: Thu February 10, 2022 02:31 AM
From: Pierre Richelle
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
Hi Anurag,
for the form part, you might use the fonction encodeURIComponent as follows:
var details = { 'userName': 'test@gmail.com', 'password': 'myPwd', 'grant_type': 'password'};var formBody = [];for (var property in details) { var encodedKey = encodeURIComponent(property); var encodedValue = encodeURIComponent(details[property]); formBody.push(encodedKey + "=" + encodedValue);}formBody = formBody.join("&");context.message.body.write(JSON.stringify(formBody));
------------------------------
Pierre Richelle
IBM Hybrid Cloud Integration Specialists
IBM
+32474681892
Original Message:
Sent: Wed February 09, 2022 02:05 PM
From: Steve Linn
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
Hi Anurag,
The parameters are simply a posted body of the formparam1=value1[¶m2=value2&etc ...]
where you could simply write a GatewayScript policy to construct this string and write it to message.body by using an apim.setvariable ('message.body', yourstring) (v5/v5c) or for the api gateway, context.message.body.write(yourstring). Don't forget to also set your content type using apim.output(`x-www-form-urlencoded`) (v5/v5c) or context.message.header.set('Content-Type', `x-www-form-urlencoded`) in the api gateway. The subsequent invoke policy will consume message.body and will send it to your target url.
Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Sat February 05, 2022 07:03 AM
From: Anurag Gupta
Subject: How to invoke target-url / api with x-www-form-urlencoded parameters
I want to invoke target url with some x-www-form-urlencoded parameters,
I tried to work around with some gateway scripts didn't worked out in favor.
Also is it possible to use curl command using gateway script.
------------------------------
Anurag Gupta
------------------------------