Apigee: Populating json object as value for http form data field

Hello All,

I have a http backend that accepts form data. I need to call this endpoint (from service callout policy) before calling the actual target. There is one form field that requires an entire json object as value. I have been trying to populate it using AssignMessage and Javascript policies(using JSON.Stringify) before servicecallout policy, but its not working.  The formdata goes as url endcoded string and the target throws 400 bad request error. Not sure how to set it and need help. Attached the Service call out policy XML below.  Please check <FormParam name="form-data"> for the data i need to send to backend.

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout continueOnError="false" enabled="true" name="SC_Call_Service">
    <DisplayName>SC_Call_Service</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="formRequest">
        <Set>
            <FormParams>
                <FormParam name="form-data"><![CDATA[{"foo": ["abcd"],"bar": ["efgh"],
    "html": "<html><body><h1>Hello</h1></body></html>","platform": "Apigee",
    "project": "Apigee","priority": "1"}]]></FormParam>
            </FormParams>
            <Headers>
                <Header name="Authorization">Bearer {token}</Header>
                <Header name="Content-Type">multipart/form-data</Header>
            </Headers>
        </Set>
    </Request>
    <!-- <Response>calloutResponse</Response>-->
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://dummy.url.com</URL>
    </HTTPTargetConnection>
</ServiceCallout>

 

 

Solved Solved
0 3 270
2 ACCEPTED SOLUTIONS

When you add <FormParams>, Apigee sets the request's Content-Type header to application/x-www-form-urlencoded before sending the message to the target service (see docs). It looks like you're trying to assemble a Multi-Part form. Perhaps you should try this.

View solution in original post

Yes - the encoding you are describing is happening because Apigee is using content-type application/x-www-form-urlencoded . But I think you want multipart/form-data .

For the former, the data will be posted as a url encoded string. For the latter, it is a multi-part format, with a boundary, and the individual parts do not get encoded.

I see in your ServiceCallout that you are setting the content-type header to multipart/form-data . That in itself does not tell Apigee to "not encode the form params". If you use Set/FormParams, you will always get application/x-www-form-urlencoded , and Apigee will always url-encode the data for each formparam. Later setting the content-type header to something different, does not change that.

ok, so how do you do what you want? To state it clearly, I think you want to use ServiceCallout to send out a request with content-type = multipart/form-data .

As I said above, you cannot "build" the form using Set/FormParams .

You can manually construct a multipart/form-data payload using a JavaScript callout. Example here. or here. The caveat here is that if you use JavaScript, all of the "parts" must have TEXT data types. You cannot include "parts" that represent  octet streams like images, PDFs, or other "binary" formats.  If you need to send out a multipart/form-data payload that encodes octet-streams, then you need to resort to a Java or Python callout. Here is a Java callout that will help. It has a full readme.

View solution in original post

3 REPLIES 3

When you add <FormParams>, Apigee sets the request's Content-Type header to application/x-www-form-urlencoded before sending the message to the target service (see docs). It looks like you're trying to assemble a Multi-Part form. Perhaps you should try this.

Yes - the encoding you are describing is happening because Apigee is using content-type application/x-www-form-urlencoded . But I think you want multipart/form-data .

For the former, the data will be posted as a url encoded string. For the latter, it is a multi-part format, with a boundary, and the individual parts do not get encoded.

I see in your ServiceCallout that you are setting the content-type header to multipart/form-data . That in itself does not tell Apigee to "not encode the form params". If you use Set/FormParams, you will always get application/x-www-form-urlencoded , and Apigee will always url-encode the data for each formparam. Later setting the content-type header to something different, does not change that.

ok, so how do you do what you want? To state it clearly, I think you want to use ServiceCallout to send out a request with content-type = multipart/form-data .

As I said above, you cannot "build" the form using Set/FormParams .

You can manually construct a multipart/form-data payload using a JavaScript callout. Example here. or here. The caveat here is that if you use JavaScript, all of the "parts" must have TEXT data types. You cannot include "parts" that represent  octet streams like images, PDFs, or other "binary" formats.  If you need to send out a multipart/form-data payload that encodes octet-streams, then you need to resort to a Java or Python callout. Here is a Java callout that will help. It has a full readme.

I dont have a requirement to send octet steams, but just a json object as value.

Let me try out the javascript example and post back if it works. Thanks both @dchiesa1  and @gonzalezruben  for the replies.