Announcements
This site is in read only until July 22 as we migrate to a new platform; refer to this community post for more details.
Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Payload formparam not assigning the correct payload

I have got an assign message like below:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="am-set-request">
<DisplayName>am-set-request</DisplayName>
<Properties/>
<Set>
<Headers>
<Header name="api-key">{apikeyVar}</Header>
<Header name="Content-Type">application/x-www-form-urlencoded</Header>
</Headers>
<QueryParams>
<QueryParam name="abd">{abdVar}</QueryParam>
<QueryParam name="abc">{abcVar}</QueryParam>
</QueryParams>
<FormParams>
<FormParam name="Payload">{request.content}</FormParam>
</FormParams>
</Set>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

but when I get a payload like below:

{
"ABC": {
"message": {
"origin": "",
},
"response": {
"messages": [
{
"messageId": "message123",
"message": "<ns0:ABC xmlns:ns0=\"urn:example.com:fin:12345:CUST\"><Tag0> <Tag1>12344</Tag1> <Tag2>B123456</Tag2> <Tag3/> <Tag4/> <Tag5>44444</Tag5> </Tag0></ns0:ABC>"
}
]
}
}
}


the apigee confuses the = sign and assumes there are 2 formparams. I had to use a workaround like below to resolve this:
context.setVariable("request.formparam.Payload",JSON.stringify(JSON.parse(context.getVariable("request.content"))));

Is there some better solution for this? or is the Payload formparam assignment in the AM policy wrong?
Thanks in advance.

Solved Solved
2 4 768
1 ACCEPTED SOLUTION

hmmm

what I understand you're doing:

  1. you have an inbound request payload with content-type:application/json
  2. you want to modify that request message so that the content-type becomes application/x-www-form-urlencoded
  3. you want to take the entire original request request body content (request.content), which is json, and use that as the value for a single form parameter. Essentially replacing the json content with form content.
  4. And you also want to add some query params
  5. and then send that to some remote target

is that about right?

And also, the JSON actually wraps some XML!! Amazing! XML, wrapped in JSON, then encoded as a form param. (If there were an award for using the most data formats in one message, you would win!)

What you're doing is ... unorthodox. A little bit unique. First question: Are you sure you want to do it that way? If I were an architect on a project , in which someone proposed doing this, I would ... ask that person to re-consider. The issue you're running into is just ONE of the reasons why it's probably not the best idea. 

I tried what you tried, and it MOSTLY works. In fact I don't see a problem with the equals sign at all. You said "the apigee confuses the = sign and assumes there are 2 formparams." but that is a conclusion, not an observation. What did you observe that lead you to the conclusion that "apigee is confused"? My observation shows that the form param gets appropriately set. Subsequent to the AssignMessage, my request body looks like this:

 

Payload=%7B%20%20%22ABC%22%3A%20%7B%20%20%20%20%22message%22...

 

...which looks correct to me. All the stuff after the equals sign is an encoded JSON payload.

But there is one nuance. One thing I had to change. By using the Set element in AssignMessage, you are setting the content-type and setting the formparam. But you haven't removed the original json content. So there is still a JSON body on the message. You need to remove the original content, and then set the form param. You can remove the payload body within AssignMessage like this:

 

<AssignMessage continueOnError="false" enabled="true" name="AM-Transform-Message">
  ...
  <Remove>
    <Payload/>
  </Remove>

 

But removing the original content means it will no longer be available in the variable request.content. request.content will return the empty string. So you need to save the original content in a different variable, then remove it, then set the form param. like this:

 

<AssignMessage name="AM-Transform-Message">
  <AssignVariable>
    <Name>retained-payload</Name>
    <Ref>request.content</Ref>
  </AssignVariable>
  <Remove>
    <Payload/>
  </Remove>
  <Set>
    <Headers>
      <Header name="api-key">{apikeyVar}</Header>
      <Header name="Content-Type">application/x-www-form-urlencoded</Header>
    </Headers>
    <QueryParams>
      <QueryParam name="abd">{abdVar}</QueryParam>
      <QueryParam name="abc">{abcVar}</QueryParam>
    </QueryParams>
    <FormParams>
      <FormParam name="Payload">{retained-payload}</FormParam>
    </FormParams>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <!--
      OMIT THIS. IT DOES NOTHING.
  <AssignTo createNew="false" transport="http" type="request"/>
  -->
</AssignMessage>

 

View solution in original post

4 REPLIES 4