Attempting to POST attachment to 3rd party endpoint failure

sivasurya
Kilo Contributor

Hello,

I am attempting to POST attachments from ServiceNow to OpsGenie.

I have gotten it to work via PostMan but when I try in ServiceNow, it results in the following error message:

Response status: 413, body: {"message":"The current request is not a multipart request","took":0.003,"requestId":"5e54093d-0fa4-4f60-8535-7857b2b7dd73"}

How my code works:

1) Business rule on sys_attachment table that encodes the file in base64 then sends that, along with the attachment sys_id to a script include

2) Script include receives that info and then creates the REST call, which it fires off to OpsGenie

Here is the relevant portion of the BR code:

// 2) Now that we've confirmed it's an OpsGenie inc, fire the REST call
	gs.log('OpsGenie Create Attachment Alert: firing REST call from ZG - Send to OpsGenie BR on sys_attachment table','x_86994_opsgenie');
	
	var StringUtil = new GlideStringUtil();
	var sa = new GlideSysAttachment();		
	var binData = sa.getBytes(current);
	var encData = StringUtil.base64Encode(binData);
	var client = new x_86994_opsgenie.OpsGenie_Client();		
	
	client.postAttachmentToOpsGenieAlertAPI(current.sys_id, gr.number,encData,current.content_type);
	gs.log("5 step","x_86994_opsgenie");

 

Script include code:

postAttachmentToOpsGenieAlertAPI: function(attach_sys_id, incNumber,encData,content_type){
		try {
			gs.info("1 Entering postAttachmentToOpsGenieAlertAPI","OpsGenie_Client");			
			// build the body, just needs to be the incNumber
			var bodyContent = {
				"alertIdentifier": "INC1102325",
				"file":encData
			};
			var bodyContentJSON = new global.JSON().encode(bodyContent);
			// build out our subEndPoint to fit into: ${endPoint}/v2/alerts${subEndPoint}
			// target: https://api.opsgenie.com/v2/alerts/:alertIdentifier/attachments
			// so build out: /:alertIdentifier/attachments
			var subEndPoint = "/" + incNumber + "/attachments";
			gs.info("Body:\n" + bodyContentJSON + "\nincNumber:\n" + incNumber + "\nencData:\n" + encData + "\ncontent_type:\n" + content_type,"OpsGenie_Client");
				
				
			// create the REST message
			var rest = new sn_ws.RESTMessageV2('x_86994_opsgenie.OpsGenie Alert API Endpoint', 'post');
			rest.setRequestHeader("Content-Type", content_type);
			rest.setRequestHeader("Authorization", "GenieKey " + this.apiKey);
			rest.setQueryParameter("alertIdentifierType", "alias");
			rest.setQueryParameter('file',encData);			
			rest.setStringParameter("endPoint", this.endpoint);
			rest.setStringParameter("subEndPoint", subEndPoint);
			rest.setRequestBody(bodyContentJSON);			
			
			// POST it
			gs.info("Posting attachment " + attach_sys_id + " from " + incNumber + " to " + rest.getEndpoint(),'OpsGenie_Client');
			var response = rest.execute();
			
			// Parse response
			var responseBody = response.getBody();
			var httpStatus = response.getStatusCode();

			var responseLogMessage = "Response status: " + httpStatus + ", body: " + responseBody;

			if(!httpStatus.toString().startsWith("2")){
				gs.error(responseLogMessage,'OpsGenie_Client');
			} else{
				gs.info(responseLogMessage,'OpsGenie_Client');
			}
		}
		catch(ex) {
			var message = ex.getMessage();
			gs.error("Exception occured: ", "OpsGenie_Client" + ex);
		}
	},

 

I'm not sure why it's returning a 413: current request is not a multi-part request. I verified that the data is being encoded properly and I am able to decode it. From what I found online, that error code occurs either when the content-type is not set correctly, or when the file is missing, but the file is being set in the query param (as the documentation states it should be) and in the body (something I was just testing out).

Thanks!

9 REPLIES 9

Ankur Bawiskar
Tera Patron
Tera Patron

Hi Surya,

I think the 3rd party system accepts data into multipart form data but you are not sending it in multipart

multipart/form-data is used for large binary data handling

Do you have the sample request shared by the 3rd party team so that you would know how to send the attachment data along with other information?

Best method is ask for sample request body to better know how and where to send the data

Sample multi-part form data request body looks like this; the --AAA is the boundary and says that it is the separating the data into the body

Example: below

pdf -> contentType = 'application/pdf';

doc/docx -> contentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';

Sample Content Body:

--AAA
Content-Type: application/json
Content-Disposition: form-data

{

"alertIdentifier": "INC1102325"

}

--AAA
Content-Type: application/pdf
Content-Disposition: file; filename="hello.pdf";documentid=1
Content-Transfer-Encoding: base64

${encData{

--AAA--

In the http post method in rest message add this headers

find_real_file.png

Mark Correct if this solves your issue and also mark Helpful if you find my response worthy based on the impact.
Thanks
Ankur

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

Hi Ankur,

Here is the documentation for the request (create alert attachment):

 

https://docs.opsgenie.com/docs/alert-api-continued#section-create-alert-attachment

 

You may be right about it being forced into multipart/form-data. I would be surprised though as I thought it would have supported more formats. Any idea how to encode in multipart/form-data request in ServiceNow?

Here's what I've tried  doing so far:

 

postAttachmentToOpsGenieAlertAPI: function(attach_sys_id, incNumber,encData,content_type,file_name){
		try {
						
			// build the body, just needs to be the incNumber
			var bodyContent = {
				"alertIdentifier": "INC1102325",
				"file":encData
			};
			var bodyContentJSON = new global.JSON().encode(bodyContent);
			// build out our subEndPoint to fit into: ${endPoint}/v2/alerts${subEndPoint}
			// target: https://api.opsgenie.com/v2/alerts/:alertIdentifier/attachments
			// so build out: /:alertIdentifier/attachments
			var subEndPoint = "/" + incNumber + "/attachments";
			
				
				
			// create the REST message
			var rest = new sn_ws.RESTMessageV2('x_86994_opsgenie.OpsGenie Alert API Endpoint', 'post');
			rest.setRequestHeader("Content-Disposition","form-data"); // added
			rest.setRequestHeader("Content-Type", "multipart/form-data; boundary=-----WebKitFormBoundaryAAA");	// changed from "content_type"		
			//rest.setRequestHeader("Content-Type", content_type);
			rest.setRequestHeader("Authorization", "GenieKey " + this.apiKey);
			rest.setQueryParameter("alertIdentifierType", "alias");
						rest.setStringParameter("endPoint", this.endpoint);
			rest.setStringParameter("subEndPoint", subEndPoint);
			// trying to add boundaries here
			bodyContentJSON = "-----WebKitFormBoundaryAAA\nContent-Type:application/json\nContent-Disposition:form-data\n" + bodyContentJSON + "\n-----WebKitFormBoundaryAAA\nContent-Type:" + content_type + "\nContent-Disposition:file;filename=" + file_name + ";documentid=1\nContent-Transfer-Encoding:base64\n-----WebKitFormBoundaryAAA--";
			rest.setRequestBody(bodyContentJSON);
			
			gs.info("Body:\n" + bodyContentJSON);
			
			// POST it
			gs.info("Posting attachment " + attach_sys_id + " from " + incNumber + " to " + rest.getEndpoint(),'OpsGenie_Client');
			var response = rest.execute();
			
// there's more but I took it out of the ServiceNow community post
	},

 

Now, my response from OpsGenie is:

 

Response status: 404, body: {"message":"No handler found","took":0.0,"requestId":"ac6bdcd7-b6f9-43eb-a1cb-dac3ecf04ec8"}

 

I'm guessing that's because it's not parsing the boundaries?

Hi Surya,

At least now you are getting some response and no error for multi-part form data

check what is the request body being sent using 

gs.info('Request Body sent is: ' + rest.getRequestBody());

this will help you knowing whether boundary is set properly or not

Mark Correct if this solves your issue and also mark Helpful if you find my response worthy based on the impact.
Thanks
Ankur

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader