Construct and post as Multi part request

@Dino

First off thankyou so much for helping us and the community.

Continuation to below post we need to send the message as multi part request.

https://community.apigee.com/questions/56914/decode-base64-image-in-apigee.html

We did decode the image, construct the multi part using JS & assign as below but somehow backend api is not really happy with the request. Wondering if below is good or something needs to be corrected?

Backend api expects as - Image * file (formData)

Tested using POSTMAN using form-data attachment simply works but while doing below sequence is causing issues.

Not sure how to be sure on content-length?

In general can you check and see what could be potential issues?

==

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout async="false" continueOnError="false" enabled="true" name="Java-Callout-1">
    <DisplayName>Java Callout-1</DisplayName>
    <Properties>
        <Property name="action">decode</Property>
        <Property name="mime-type">image/jpeg</Property>
    </Properties>
    <ClassName>com.google.apigee.edgecallouts.Base64</ClassName>
    <ResourceURL>java://edge-custom-base64-1.0.3.jar</ResourceURL>
</JavaCallout>

==

var boundary = Math.random().toString().substr(2);
var multipart ="";
multipart = "----------------------------" + boundary+"\r\n"
           + "Content-Disposition: form-data; name=\"image\"; filename=\"front_image.jpeg\"" +"\r\n"
           + "Content-Type: image/jpeg"
           + "\r\n\r\n" + request.content + "\r\n"
           + "----------------------------" + boundary+"\r\n";
var n = multipart.length;
context.setVariable("multipart", multipart);
context.setVariable("boundary", boundary);
context.setVariable("multipartLength", n);
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-3">
    <DisplayName>Assign Message-3</DisplayName>
    <Properties/>
    <Add>
        <Headers>
<Header name="Content-Type">multipart/form-data;boundary=----------------------------{boundary}</Header>
        </Headers>
    </Add>
    <Payload variablePrefix="@" variableSuffix="#">
            @multipart#
        </Payload>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Solved Solved
1 7 1,907
1 ACCEPTED SOLUTION

Not sure exactly, but here's what I think

  • This part

    multipart/form-data;boundary=----------------------------{boundary}
    	

    seems hard to debug. The basic format requires "double dash" followed by the boundary string. If you include dashes in the boundary string it makes it difficult to verify that the boundary is being formatted correctly with the required double-dash prefix. We are left with counting tiny little dashes and trying to remember, should it be 24? or 26? If you confine the boundary string to just alphanumeric, then it's easier to see. I think you want

    multipart/form-data;boundary={boundary}
    	

    and then you'd need to also modify the JavaScript to be like this:

    var boundary = Math.random().toString().substr(2);
    var multipart = "--" + boundary + "\r\n"
               + "Content-Disposition: form-data; name=\"image\"; filename=\"front_image.jpeg\"" + "\r\n"
               + "Content-Type: image/jpeg"
               + "\r\n\r\n" + request.content + "\r\n"
               + "--" + boundary + "--\r\n";
    	

    Note: the ending boundary needs to have a final trailing "--" prior to the CR/LF

  • For the AssignMessage / Payload, I would use something like this:

        <Payload>{multipart}</Payload>
    	
  • You should be able to ignore content-length and just let Apigee auto-compute it.

It seems like it is a "mutlipart" form with just a single part. Is that right?

View solution in original post

7 REPLIES 7

How content length is calculated? It is the only header which is different? Any one tested posting multi part image as form data after decoding ?

@Dino: Can you take a look and respond when you get a chance

Also opened a ticket 1442275 for help.


Not sure exactly, but here's what I think

  • This part

    multipart/form-data;boundary=----------------------------{boundary}
    	

    seems hard to debug. The basic format requires "double dash" followed by the boundary string. If you include dashes in the boundary string it makes it difficult to verify that the boundary is being formatted correctly with the required double-dash prefix. We are left with counting tiny little dashes and trying to remember, should it be 24? or 26? If you confine the boundary string to just alphanumeric, then it's easier to see. I think you want

    multipart/form-data;boundary={boundary}
    	

    and then you'd need to also modify the JavaScript to be like this:

    var boundary = Math.random().toString().substr(2);
    var multipart = "--" + boundary + "\r\n"
               + "Content-Disposition: form-data; name=\"image\"; filename=\"front_image.jpeg\"" + "\r\n"
               + "Content-Type: image/jpeg"
               + "\r\n\r\n" + request.content + "\r\n"
               + "--" + boundary + "--\r\n";
    	

    Note: the ending boundary needs to have a final trailing "--" prior to the CR/LF

  • For the AssignMessage / Payload, I would use something like this:

        <Payload>{multipart}</Payload>
    	
  • You should be able to ignore content-length and just let Apigee auto-compute it.

It seems like it is a "mutlipart" form with just a single part. Is that right?

thanks for your reply..Ignore the boundary as was just trying out all sort of things to make it work..

Infact it is such a hassle to do in apigee..thinking to avoid apigee. Idea was to direct invocation from mobile to gateway for check deposits for vendor api but now planning to have soa component which take care and do a pass thru (which i hate it to add one more layer)..Will give a try a day more somehow it doesn't work.

Using plain java decode,creating multi part works absolutely fine.

Form data with attachment as pass thru works via apigee works fine.

issue with base64 decode and creating a multi part is such a pain & doesn't work.

Is there a way to replicate internally and see if it actually works? Can you see if it is doable?

Really appriciate your help.

Sorry! Looking at your code again, I now realize you are DECODING with the Java callout. The result is implicitly placed into request.content. This result is a byte array.

but in JavaScript you are doing this:

var multipart = "--" + boundary + "\r\n"
           + "Content-Disposition: form-data; name=\"image\"; filename=\"front_image.jpeg\"" + "\r\n"
           + "Content-Type: image/jpeg"
           + "\r\n\r\n" + request.content + "\r\n" 
        ...

In other words, this is a string concatenation. request.content is not a string, though. It's an array of bytes. So I think that approach - creating a byte array in Java and then consing up the message in Javascript - is doomed to failure.

The reason we must resort to Java callout to do the base64 encode/decode is that JavaScript in Apigee Edge is not well suited to handling byte arrays. Doing it all in Java would work fine of course.

I think there is an opportunity to write a re-usable Java callout that would create a multipart/form-data message in its entirety. This would eliminate the need for concatenating strings with byte arrays in JS. Making a single-use Java callout just for you would be simple. But I'd need to think a little more about generalizing it.

Let me look. It ought to be quick.

Thanks Dino.We did try creating the java code which decodes & create multi part/form-data (will attach to ticket #1442275)but didn't help & not sure if we are missing something while constructing multi-part.Is there a way to validate internally?

Much Appreciated Dino.

Try this.https://github.com/DinoChiesa/Apigee-Java-Simple-MultipartForm

ps: I'm leaving for the weekend right now. In the USA this is a holiday weekend; I will be back Tuesday.