Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
platinumicef
Explorer
Recently I has been working on synchronous integration scenario which involves sending JSON with some files (usually PDFs) attached using REST adapter. Attachments are accepted by the receiver through HTTP POST request with multipart/form-data encoding. Attachment filenames must be preserved for receiver system since they are stored and displayed to end-user. Response contains JSON with operation status and error log (if any). Sender system is SAP S/4HANA with ABAP-proxy generated based on message type defined in SAP PO.

The challenge was to fulfill the task using only standard SAP PO REST adapter without use of any adapter modules and custom JAVA mapping to build the request body.

Here are my findings.

SAP PO Configuration


I am using SAP PO 7.50 SP24 so if you have earlier releases your milage may vary.

REST Receiver communication channel for receiving system is created. In order to support sending and receiving JSON format you need to select appropriate "Data Format" = JSON for Request and Response configuration sections. Also "Support attachments" must be selected for channel in order to push any attachments to the receiver. Multipart content type "multipart/form-data" is also selected as per receiver system requirement.

Other communication channel properties are not relevant to this blog entry but are not related to attachments being sent.


REST Receiver Communication Channel


Operation Mapping and Message Mapping work only on main message part, no attachments. No adjustments were made to Sender Communication Channel (SOAP-XI Channel) or ICo in order to support attachments.

Code on ABAP side (SAP S/4HANA)


If you follow official guides and articles when dealing with attachments you will get an attachment with internally generated name (specified as Content-ID in XI). This autogenerated name is then passed to the receiver which is not acceptable for this integration scenario.


Message attachments in Message Monitor


In order to fix the issue attachment needs to be added to ABAP-proxy instance in a specific way which exposes "Content-Disposition" attribute of the payload. Below is code required to create attachment object, set up attachment headers correctly and send attachment alongside main payload.

Filename may include non-Latin characters. If this is the case, filename must be encoded according to RFC 2047 and RFC5987, where UTF-8 is used as target encoding.
DATA lv_filename TYPE string " filename to be sent
DATA lv_xstring TYPE xstring " binary content of the file to be sent

" generated ABAP-proxy
DATA(lo_proxy) = NEW zco_create_document_request_ou( ).

DATA :
" support for XI attachment protocol
lo_attch_protocol TYPE REF TO if_wsprotocol_attachments,
" request message type
ls_request TYPE zcreate_document_request,
" response message type
ls_response TYPE zcreate_document_confirmation.

" encodes filename for XI
" see details below
DATA: lv_encoded_filename TYPE string.
PERFORM encode_rfc2047_rfc5987 USING lv_filename CHANGING lv_encoded_filename.

" get MIME type based on filename (extension).
" if extension is missing or unknown -- generic application/octet-stream will be returned.
DATA(lv_content_type) = ||.
CALL FUNCTION 'SKWF_MIMETYPE_OF_FILE_GET'
EXPORTING
filename = p_name " File Name
IMPORTING
mimetype = lv_content_type. " MIME Type

" create attachment object
DATA(lo_payload) = NEW cl_xms_payload( ).
lo_payload->if_xms_payload~setpayloadtype( 'A' ). " ApplicationAttachment
lo_payload->if_xms_payload~setbinarycontent(
data = lv_xstring " binary content
type = lv_content_type " MIME content type
). "
lo_payload->if_xms_payload~set_disposition( |form-data; name="filename"; { lv_encoded_filename }| ).
lo_payload->if_xms_payload~setdocumentname( p_name ). " visible in SXI_MONITOR

" add attachment object to ABAP-proxy instance
DATA(lo_attachment) = NEW cl_ai_attachment( p_from_type = 'B' ).
lo_attachment->set_payload( lo_payload ).
lo_attch_protocol ?= lo_proxy->get_protocol( if_wsprotocol=>attachments ).
lo_attch_protocol->set_attachments( VALUE #( ( lo_attachment ) ) ).

" here <ls_request> must be filled as per functional specification
" skipped as non-essential

" call ABAP-proxy
lo_proxy->create_document_request_out_sy(
EXPORTING
output = ls_request
IMPORTING
input = ls_response ).

**********************************************************************

FORM encode_rfc2047_rfc5987 USING i_filename
CHANGING i_encoded_filename TYPE string.

" encodes filename according to RFC 2047 and RFC 5987
" uses UTF-8 encoding and BASE64 encoding
" returns correct header for Content-Disposition MIME field
" FORM must be used if filename may include symbols outside ISO-8859-1 (Latin 1) codepage

DATA(lv_filename_to_encode) = CONV string( i_filename ).
DATA(lv_base64_filename) = cl_http_utility=>if_http_utility~encode_x_base64(
cl_http_utility=>if_http_utility~encode_utf8(
lv_filename_to_encode
)
).
DATA(lv_rfc5987_filename) = escape( val = lv_filename_to_encode format = cl_abap_format=>e_xss_url ).

i_encoded_filename = |filename="=?utf-8?B?{ lv_base64_filename }?="; filename*=UTF-8''{ lv_rfc5987_filename }|.

ENDFORM.



Demonstration


For demonstration purposes I have sent a message which contains main payload (to be converted to JSON) and one PDF attachment. Below are screenshots from SXI_MONITOR showing example message with attachment:


SXI_MONITOR message view



SOAP Manifest



NWA Message Monitor showing attachment


If you open message in Message Monitor -- attachment will be listed with correct name.


Message Monitor -- attachment view


Below is HTTP dump for the request to the receiving system. Filename is transmitted in UTF-8 encoding but decoded from RFC 2047 encoding during HTTP call.


Setting Content-Disposition for main payload (OPTIONAL)


Receiving system requested that main payload should have a specific constant value in its Content-Disposition header instead of automatically generated one. Easiest way to archive it is to modify this field on Receiver Channel side using standard adapter module MessageTransformBean.

In order to replace Content-Disposition for main payload, add module AF_Modules/MessageTransformBean and specify parameter Transform.ContentDisposition with requested value (for example -- form-data; name="request").


Adapter Module configuration


Content-Disposition for main payload is successfully replaced with a constant:



UTF-8 support


Below is an example message showing full UTF-8 support. In this example file has Cyrillic characters in its name:


SXI_MONITOR message view



Message manifest



NWA Message Monitor -- Attachment view


NOTE: this screen is broken -- it will not show UTF-8 encoded text. Screen interprets this field as Latin-1 codepage so it shows up broken. This only affects the display, internally filename is interpreted correctly. Once SAP releases a fix for this issue, I will update the article.


NWA Message Versions -- Attachment view


Filename is passed by REST adapter to the receiving system as UTF-8 string and as RFC 5987-encoded one:



Conclusion


Described method works great with REST Receiver adapter and should work the same way (albeit with some caveats) with all receiver adapters which natively support attachments -- such as SOAP, File and Mail adapters.

Thank you for your attention!

Hope this article will prove useful in your integration adventures!
3 Comments
Nikiforos
Explorer
0 Kudos
Great Blog! Worked like a charm! Thank you for writing it 🙂
ramki_saper12
Member
0 Kudos
Hi Marat,

Thank you so much for the nice blog.

I need to send a CSV file which is placed in AL11, through XI as a rest service .

Can you provide PI structure attributes
    ls_request        TYPE zcreate_document_request, 

and assignments.

 

Thankyou.

 

 

 
platinumicef
Explorer
0 Kudos
As written in the article:
  " here <ls_request> must be filled as per functional specification
" skipped as non-essential

If you need to send one file as binary attachment and one as supplimentary message (XML, JSON or whatever), then you can define the structure for supplimentary message as requested in functional specification.
Labels in this area