Skip to Content
Technical Articles
Author's profile photo Luke Allen

REST Form Submission with dynamic name and filename attributes

Introduction

 

I recently had a requirement to submit xml payload as a csv file embedded in an HTTP form to a REST endpoint. Based on the vendors documentation I had to achieve something similar to the below:

*REQUEST HEADER*
Key Value
Content-Type multipart/form-data; boundary=—-WebKitFormBoundary123456789
Accept text/plain
*REQUEST BODY*
——WebKitFormBoundary123456789
Content-Disposition: form-data; name=”file“; filename=”Import TEST.txt
Content-Type: text/plain
200000,55555555,01,200000,55555554,00000000100,”The Victorian Soci”,00009662
——WebKitFormBoundary123456789–

This posed some issues since the standard form submission for the REST adapter auto populates the name and filename attributes of the Content-Disposition attribute with the SAP generated attachment name.

Below I have shared the possible solutions I investigated and the results obtained from each one, this will hopefully help you if facing similar issues.

 

Solutions

After research I found three potential methods explained below, note all screenshots are based on NWDS 7.5 and from proof of concepts I developed:

1) Use REST Receiver Adapter with Attachment attribute set and Module to format data

 

Since SAP PO 7.50 SP07 a new functionality is added to the REST adapter that allows sending and receiving MIME multipart messages (see SAP Note 2365727)

Ticked support Attachments and set multipart content type to ‘multipart/form-data’

Because the outputted data is not xml and to set Data Format to JSON

Set the below modules

StrictXml2PlainBean – used to convert payload to csv

MessageTranformBean – used to change the Forms Content Disposition to the required file and filename (PO sets these initially to the system generated payload name)

FormDataBean – although the ‘Support Attachment’ was set on the REST adapter it did not output the final message in an HTTP form, adding an additional form content using this bean resolved that issue.

 

Result: Although the above worked the filename could not be set dynamically

2) Create a new attachment with dynamic file name and do a payload swap

This is explained in blog https://blogs.sap.com/2019/04/23/csv-multi-part-form-data-upload-as-attachment-using-http_aae-adapter-in-sap-pi-7.5/

Basically, this method uses a UDF to create a new csv attachment based on the original payload. The attachment can be added with a specified filename read from the payload/ASMA. The Payload swap bean is then used to swap the message payload with this new attachment. Again for the REST adapter the support attachments and Data Format – JSON should be set.

 

Result: Although a dynamic filename had been achieved for my particular scenario the form name had to be set to “file”. I tried adding the MessageTransformBean and setting

This however removed the filename element of the ContentDisposition so was not workable.

3) Create Form in Java Mapping

After reading blog https://blogs.sap.com/2014/09/12/html-form-upload-using-http-plain-adapter-with-java-mapping/ I decided to try the Java mapping route.

Again the REST Adapter Data Format was set to JSON (XML setting complains about none valid xml)

‘Support Attachments’ unticked

 

The form was set on the HTTP Headers tab instead

 

As a proof of concept the below simplified JAVA mapping was created.

package com.mapping;

import java.io.OutputStream;

import com.sap.aii.mapping.api.AbstractTransformation;

import com.sap.aii.mapping.api.StreamTransformationException;

import com.sap.aii.mapping.api.TransformationInput;

import com.sap.aii.mapping.api.TransformationOutput;

 

public class FormMapping extends AbstractTransformation {

@Override

public void transform(final TransformationInput in, final TransformationOutput out) throws StreamTransformationException {

 

final String LINE_FEED = “\r\n”;

String RESULT = “”;
String boundary = “–SAP_e9943b97-7668-11ea-9604-0000005b75e1_END”;
String contentDisposition = “Content-Disposition: form-data;name=\”file\”;filename=\”TestFile.txt\””;

String contentType = “Content-Type: text/plain”;

String content = “555555,55550000,120000,TEST SUPPLIER,11102000000000”;

try {

OutputStream outputstream = out.getOutputPayload().getOutputStream();

RESULT = boundary + LINE_FEED + contentDisposition + LINE_FEED + contentType + LINE_FEED + LINE_FEED + content + LINE_FEED + LINE_FEED + boundary
+ “–” + LINE_FEED;
outputstream.write(RESULT.getBytes());

} catch (Exception exception) {

getTrace().addDebugMessage(exception.getMessage() + RESULT);

throw new StreamTransformationException(exception.toString() + RESULT);

}

}

}

Result: The above code allows us to set both the file and filename of the Content-Disposition. This worked successfully. Note the ‘boundary’ set on the HTTP header and in the Java code must match. Not sure if the boundary needs to be dynamic or can be static? In my final code I set the boundary to be the MessageID GUID and created the csv content from the source payload.

 

Conclusion

There may be other ways to achieve the above but based on the three methods I tried the following conclusions can be drawn:

  • For a static name and filename then method 1 can be used
  • For a static name and dynamic filename then method 2 can be used
  • For a dynamic name and filename then method 3 is the best solution

 

 

Assigned Tags

      11 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Luke Allen
      Luke Allen
      Blog Post Author

      Although showing correct in edit mode I noticed double dashes are not showing correctly in the sample code, screenshot attached for clarity

      Author's profile photo Anik Bose
      Anik Bose

      Thanks for the informative document .

      Author's profile photo Pavan Kumar GVN
      Pavan Kumar GVN

      Hi Luke Allen,

      thank you for the great information , i have a similar requirement and i am using the second method you have given. below is my expected structure. I am receiving internal server error while trying to push . Could you please help ?

       

      ----------------------------550670562156940361255539

      Content-Disposition: form-data; name="ImportType"

       

      ImportFXRate

      ----------------------------550670562156940361255539

      Content-Disposition: form-data; name="Name"

       

      Name97

      ----------------------------550670562156940361255539

      Content-Disposition: form-data; name="File"; filename="ImportFXRateTemplate.csv"

      Content-Type: text/csv

       

      1/1/2015,EUR,USD,1.21002

      1/1/2015,CNY,USD,0.16248

       

      ----------------------------550670562156940361255539

      Author's profile photo Luke Allen
      Luke Allen
      Blog Post Author

      Difficult to comment on individual scenarios, what I would suggest though is to send a test submission using SOAPUI or POSTMAN check the generated HTTP request and then use SAP XPI_INSPECTOR tool to capture the HTTP request from PI and then compare the two feeds.

      Author's profile photo Rajesh PS
      Rajesh PS

      Luke Allen

      Good one luke.

       

      Well, I tried with the Java Mapping and get the below error. May need your inputs here luke.

       

      Error is  “body”:”Missing initial multi part boundary”

       

      Cheers,

      Rajesh PS

       

       

      Author's profile photo Luke Allen
      Luke Allen
      Blog Post Author

      Make sure you use the code I put in the comments, it did not show correctly in the blog.  Also note the message is sensitive to blank lines in it so be careful on the line feeds.

      Author's profile photo Rajesh PS
      Rajesh PS

      Luke Allen

      There was an issue with below string declaration(highlighted in bold). Now Looks good ?

       

      String paramName1Value = "Content-Disposition: form-data; name=\"tableId\"" + LINE_FEED + LINE_FEED + tableID;
      
      String paramName2Value = "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileNameString + "\""
      + LINE_FEED + "Content-Type: application/octet-stream" + LINE_FEED + LINE_FEED + fileContents;
      
      String boundaryStart = "--" + boundary;
      
      String boundaryEnd = "--" + boundary + "--";
      
      String requestBody = boundaryStart + LINE_FEED + paramName1Value + LINE_FEED + boundaryStart + LINE_FEED
      + paramName2Value + LINE_FEED + boundaryEnd;
      
      
      

       

      Cheers,

      Rajesh PS

      Author's profile photo Ankit Mishra
      Ankit Mishra

      Hi Luke,

       

      Thanks for a nice blog. I have tried the Java Mapping option as I found that much easier to implement. The only challenge I face is the file name, which is not getting reflected at the target side. The file name they receive is MainDocument. I'm using HTTP_AAE adapter as receiver. Below is the HTTP trace that I see under NWA.

       

      HTTP_CLIENT : 49807 REQUEST:

      ------=_Part_0_2106884828.1653572441868
      Content-Type: application/xml
      Content-ID: <payload-6f3c6964dcf911eca4740000003317e2@sap.com>
      Content-Description: MainDocument
      Content-Disposition: form-data; name="datasetFile"; filename="MainDocument"

      ----WebKitFormBoundary7MA4YWxkTrZu0gW
      Content-Disposition: form-data; name="datasetFile"; filename=Price.zip
      Content-Type: application/zip

      <Content>
      ------WebKitFormBoundary7MA4YWxkTrZu0gW--

      ------=_Part_0_2106884828.1653572441868--

      Author's profile photo Former Member
      Former Member

      Hi Luke,

      thanks a lot for a nice blog.

      I have tried the Java Mapping option and get the below error:

      "Unexpected end of MIME multipart stream. MIME multipart message is not complete"

      Could you please help ?

      Cheers,

      Raffaele

      Author's profile photo Yunze Wang
      Yunze Wang

      Hi Allen,is there any documentation for the FormDataBean,I've multi pair of key values to be submitted using form-data,I've checked the support attachment and choose the multipart/form-data,but the body transferred nothing.

      Author's profile photo Isabelle Arickx
      Isabelle Arickx

      Hello,

      There is an easier way to work with dynamic filenames in the REST adapter.

      When you add an attachment using

      lo_attachment_protocol ?= lo_proxy->get_protocol( if_wsprotocol=>attachments ).
      lo_attachment = lo_attachment_protocol->get_attachment_from_binary( data = lv_xstring type = if_ai_attachment=>c_mimetype_pdf name = 'NameOfTheAttachment' ).
      APPEND lo_attachment TO li_attachments.
      lo_attachment_protocol->set_attachments( li_attachments ).

      you can use the function module SXMB_SET_DYN_HDR_OUT right before the proxy call to set the filename (see note 2422045 - SAP NETWEAVER PI RUNTIME: Application uses dynamic header):

      ls_dynamic-param_namespace = 'http://sap.com/xi/XI/Message/30/Disposition'.
      ls_dynamic-param_name = 'NameOfTheAttachment'.
      ls_dynamic-param_value = 'form-data; name="file"; filename="DynamicFilename"'.

      APPEND ls_dynamic TO li_dynamic.

      CALL FUNCTION 'SXMB_SET_DYN_HDR_OUT'
      EXPORTING
      dynamic_t = li_dynamic
      EXCEPTIONS
      parameter_not_valid = 1
      OTHERS = 2.

      Thus you can set different filenames for different attachments.