Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
MajoMartinez
Advisor
Advisor
Hello!

In this blog post, you'll learn how to send multipart/form-data in the SAP Cloud Integration service, in this case, while integrating with the DocuSign Open Connector. In addition, you'll learn how to view and get the recipient URL of the DocuSign document, in case you want to embed it in your custom application.

Please bear in mind that this blog is for exercise purposes. Unfortunately, the Open Connector adapter in SAP Cloud Integration currently does not support sending multipart/form-data. So in this blog post, you'll find an exercise as a workaround.

Prerequisites:



  • You have a SAP BTP account or trial account. If you don’t have an account, it is recommended to start using the several SAP BTP Free-Tier services available, this tutorial can help you. If you want to use the “regular” trial account, create one by registering here.

  • You have created an SAP Integration Suite instance, with Cloud Integration and Open Connectors added as capabilities.

  • You have created a DocuSign Open Connector instance. Here, you need to get your Open Connector credentials (User, Organization and Element (a.k.a. Instance Token)

  • You have created a DocuSign template. If you want to try the exercise but don't have a DocuSign account, you can create a trial one here. If not sure how to create a template and get the template, you can follow the first steps of this previous blog post.


 

Let's start with creating the envelope


Let's create an Integration Package. I named it "DocuSign_OpenConnector".


Create an Integration Flow in the Artifacts tab.



On the Edit mode, change the Sender's name to Postman in the General tab, as we're going to test it using Postman and connect it to the start event using an HTTPS adapter.

Add an Address/Path and uncheck the CSRF protection.


Add a Content Modifier. Here we will add the headers as we needed to call the DocuSign Open Connector:

  • Authorization: <User #####, Organization #####, Element #####> (Open Connector's credentials)

  • Content-Type: multipart/form-data; boundary=-------------12345

  • accept: application/json



Change the Message Body to "Expression" and leave Exchange Property empty, we are going to pass the payload directly when calling the endpoint.


Add a Groovy Script and create a script.


Copy and paste this code:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
//Body
def body = message.getBody(String);
body = body.replaceAll("\n", "\r\n");
body = """---------------12345\r\nContent-Disposition: form-data; name="envelope"\r\n\r\n""" + body + """\r\n\r\n---------------12345--"""

message.setBody(body);
return message;
}

I was getting a 400 error "Unable to parse multipart body" in SAP Cloud Integration, despite being able to call directly the DocuSign Open Connector in the Open Connector Service. For this reason, I needed to find a workaround to pass multipart/form-data through the Integration Flow. Many thanks to my colleague Rafael Moncayo who helped me to conduct this integration step and also to this great blog post from mattisebastian

You should see it like this:


Add a Request Reply Call and connect it to the Receiver using an HTTP adapter.

Despite using an Open Connector endpoint, unfortunately -as mentioned at the beginning of the blog-, the Open Connector adapter does not support at the moment multipart/form-data. For this reason, we need to configure it using an HTTP receiver adapter.

Add your Open Connector URL, and the headers you have declared in the previous Content Modifier. You should have this adapter configured as the screenshot below:


Save and deploy your Integration Flow.

Then, go to Monitor Integration Content, select your recently deployed Integration Flow and change the Log Configuration to "Trace", we are going to test the Integration Flow.


Copy your Integration Endpoint, add your SAP Integration Suite credentials as Authorization in Postman and, add your needed Payload for creating the DocuSign envelope.

This is the Sample Payload I used. This is going to depend on how many input values you added to your DocuSign template.
{
"templateId": "<DocuSign template Id>",
"emailSubject": "DocuSign Subject From Postman",
"status": "sent",
"templateRoles": [
{
"email": "<Signer's email>",
"name": "Mariajose Martinez",
"roleName": "Signer",
"tabs": {
"textTabs": [
{
"tabLabel": "fullName",
"value": "Postman is sending this Name Value"
}
]
}
}
]
}

Test the call:


You'll get a success call, and here you can check the envelopeId. We are going to get to this part later.

You should have received the email too.



Now, let's get back to check the Trace.

Click on Monitor Message Processing and then Trace:


Check how the Payload gets embedded in the Message body.


Very good. Now let's get the Recipient URL.

 

Let's get now the Recipient URL


Let's get back to the Integration Flow, and add a JSON to XML converter. We need this to apply an XPath to create a URL property. Make sure the "Add XML Root Element" is checked.

In this case, as the Payload has many roots, SAP Cloud Integration needs the message to have a single root in the XML message. In this way, we are going to be able to get the URL property.


Add a Content Modifier. Leave the Message Header empty as we are going to reuse the ones declared in the first Content Modifier.

Go to Exchange Property and let's create the envelopeId property as shown in the screenshot, with the source value /root/envelopeId :


In the Message Body, add this JSON payload as a constant. Here we need to add a Callback URL for when the DocuSign document is already signed.

Sample Payload:
{
"authenticationMethod": "None",
"email": "<your email>",
"recipientId": "1",
"returnUrl": "https://www.sap.com/canada/index.html",
"userName": "<your DocuSign email account>"
}

Like this:


Add another Request Reply call and change the name to "Recipient URL"

Add another Receiver as DocuSign and configure the HTTP adapter.

Check that the Open Connector endpoint is a little bit different. This time we need to point to the /envelopes/${property.envelopeId}/recipient-views.

The property envelopeId is the one created in the previous Content Modifier. Type the headers again, as shown in the picture:


Save and deploy your Integration Flow.

Test it again in Postman:


With this, you are going to be able to embed this URL in your custom application if you want to.

 

Conclusions



  • You have learned how to send multipart/form-data in SAP Cloud Integration to create an envelope connecting with the DocuSign Open Connector.

  • In addition, you have learned how to get the recipient URL for cases where you want to embed the DocuSign document in your custom application.


Hope you've enjoyed this quick exercise 🙂
6 Comments
BrunoGuerrero
Advisor
Advisor
Very nice blog Majo! Thanks for sharing
Saurabh_Kabra
Participant
Hi mariajosemq741 ,

Awesome blog. While I did struggle to make the DocuSign API work but kudos to your other blog which helped me to get this set up, up and running.

Maybe someone who might face the same issue, I am attaching here a snapshot for the config to be done in OpenConnector as well as the DocuSign portal.


MajoMartinez
Advisor
Advisor
0 Kudos
Thanks for sharing, Saurabh! 🙂
VictorNoroc
Explorer
0 Kudos
Hi mariajosemq741 ,

are you aware if SAP made available the possibility to use multipart/form-data with OpenConnectors adapter in Cloud Integration?

I see that the option is there in Connection->Request Format, but when I tried it as you are doing in the blog, over groovy script, I am getting the error: "com.sap.it.rt.adapter.openconnectors.exceptions.OpenConnectorsException: Invalid Multipart Formdata Payload"

Thanks,
Victor
MajoMartinez
Advisor
Advisor
0 Kudos
Hi Victor,

Please use the HTTP adapter as a workaround, as stated above in the blog.

SAP has not yet made available the ability to work with multipart/form-data with the Open Connector adapter.

Thanks,

Mariajose
BryanPierce
Explorer
0 Kudos

Hi. Not sure if this is monitored but SAP Support referenced this blog to me for how to handle our scenario. We are looking to use the Open Connector for Microsoft Graph for posting files to SharePoint. I've also found other blogs including this one (https://community.sap.com/t5/technology-blogs-by-sap/part-3-posting-documents-to-sharepoint-create-p...) which has helped a bunch. SAP indeed says to use HTTP Adapter instead of Open Connector. I've been able to successfully build out what should be a simple iFlow per these blogs and I'm very close to success but can't past one aspect that is throwing me. I can get connectivity and authorization to the needed SharePoint location but having trouble understanding how to send the actual file content. Here is the error I'm getting from the HTTP response as well as the Groovy script I'm working with. 2024-04-09_11-33-06.jpg2024-04-09_11-33-46.jpg

/*
The integration developer needs to create the method processData
This method takes Message object of package com.sap.gateway.ip.core.customdev.util
which includes helper methods useful for the content developer:
The methods available are:
public java.lang.Object getBody()
public void setBody(java.lang.Object exchangeBody)
public java.util.Map<java.lang.String,java.lang.Object> getHeaders()
public void setHeaders(java.util.Map<java.lang.String,java.lang.Object> exchangeHeaders)
public void setHeader(java.lang.String name, java.lang.Object value)
public java.util.Map<java.lang.String,java.lang.Object> getProperties()
public void setProperties(java.util.Map<java.lang.String,java.lang.Object> exchangeProperties)
public void setProperty(java.lang.String name, java.lang.Object value)
*/
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;


def Message setHeader(Message message, String id) {

message.setHeader("Content-Type","multipart/form-data; boundary=--------------------------" + id);

return message;

}


def ByteArrayOutputStream getMultiPartBody(payload, filename, id) {

/*
body = """---------------12345\r\n
Content-Disposition: form-data; name="envelope"\r\n\r\n"""
+ body + """\r\n\r\n
---------------12345--"""
*/

String charset = "UTF-8";
def LINEFEED = "\r\n";

def output = new ByteArrayOutputStream();
output.write(("----------------------------"+ id).getBytes(charset));
output.write(LINEFEED.getBytes(charset));
output.write(("Content-Disposition: form-data; filename=\""+filename+"\"").getBytes(charset));
output.write("Content-Type: application/pdf".getBytes(charset));
output.write(LINEFEED.getBytes(charset));
output.write(LINEFEED.getBytes(charset));

output.write( payload );
output.write(LINEFEED.getBytes(charset));
output.write(LINEFEED.getBytes(charset));

output.write(("----------------------------"+ id + "--").getBytes(charset));
return output;

}


def Message processData(Message message) {

String charset = "UTF-8";
def id = "238360769909770904663504";

def map = message.getProperties();
def filename = map.get("FileName");

def payload = message.getBody((byte[]).class);
//message.setProperty("byteSize",payload.length);

def ByteArrayOutputStream output = getMultiPartBody(payload,filename,id);
message = setHeader(message, id);
message.setBody(output.toByteArray());

return message;
}