Copying attachments Rest API Post

Hi, I’m trying to copy an attachment from an issue and post it to another issue. In Script runner, the post request was structured like

def fileBody = Unirest.get("${url}").asBinary().body
def resp = Unirest.post("/rest/api/2/issue/${Issuekey}/attachments")
                    .header("X-Atlassian-Token", "no-check")
                    .field("file", fileBody, ContentType.create(attachment.mimeType as String), attachment.filename as String)
                    .asObject(List)

And I’m not quite sure how to replicate this in forge. In the Rest API Documentation, none of the examples include how to add any of the required file fields to the request. https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-attachments/#api-rest-api-3-issue-issueidorkey-attachments-post.
Any ideas on how to complete the api request? This is what I have so far.

let response = await api.asApp().requestJira(requestUrl, {
         method: "POST",
         headers: {
             "X-Atlassian-Token": "no-check"
         },
        fields: {"file", filebody, ContentType.create(attachment.mimeType as String), attachment.filename as String}
     });

*Note: the fields part is completely incorrect but it was my guess on how it can be added.

1 Like

Hi @AlexFang, that’s a good question. From looking at the docs you linked, the file field is a multipart/form-data parameter. The requestJira API is intended to wrap auth around a node-fetch API, so we should be able to do whatever node-fetch does.

From the node-fetch docs (see here), you should be able to use the form-data module to pass the required data via the body and headers. You will likely still need “X-Atlassian-Token” header still as well as the form-data headers.

Hello @kchan, Thanks for the response. I am trying to use the FormData however when I try to append to the form, I receive an error stating Arrays are not supported.
Code:

async function addAttachment(issueId, filebody, attachment) {
    const requestUrl = `/rest/api/3/issue/${issueId}/attachments`;
	const FormData = require('form-data');
	var form = new FormData();
	
	form.append("file", filebody, attachment.filename as String);
	
    // Use the Forge Runtime API to fetch data from an HTTP server using your (the app developer) Authorization header
    let response = await api.asApp().requestJira(requestUrl, {
        method: "POST",
        headers: {
            "X-Atlassian-Token": "no-check"
        },
        body: form
    });

	 console.log(`posted new attachment`);
	 console.log(`Response: ${response.status} ${response.statusText}`);
	 
     // Error checking: the Jira issue comment Rest API returns a 201 if the request is successful
     if (response.status !== 201) {
         console.log(response.status);
         throw `Unable to add attachment to issueId ${issueId} Status: ${response.status}.`;
     }

     return (await response.json());
 }

error:
ERROR 05:11:46.150 767b29705aa90066 Arrays are not supported.
Error: Arrays are not supported.
at FormData.append (webpack:///node_modules/form-data/lib/form_data.js:67)
at addAttachment (webpack:///src/index.jsx:93)
at /tmp/tunnel8aGqfkNGneRoW/index.js:18741:100
at processInitialValueAndThrow (webpack:///node_modules/@forge/ui/out/hooks/useAction.js:36)
at Object.exports.useAction (webpack:///node_modules/@forge/ui/out/hooks/useAction.js:51)
at exports.useState (webpack:///node_modules/@forge/ui/out/hooks/useState.js:6)
at Object.App [as type] (webpack:///src/index.jsx:161)
at /tmp/tunnel8aGqfkNGneRoW/index.js:30680:36
at async asyncMap (webpack:///node_modules/@forge/ui/out/reconcile.js:13)
at async /tmp/tunnel8aGqfkNGneRoW/index.js:30642:29

Hi @AlexFang, thanks for trying. Let me have a look into this to see if I can figure out a way to make this request! I’ll get back to you soon.

Hi @AlexFang, sorry for the delay, I have been very busy over the last few days. I will get to this soon!

1 Like

Hi @AlexFang, I managed to take a look at this today, and it seems that Forge doesn’t yet support multipart/form-data APIs. This is because we implement a sandbox around the app developer code to be able to enforce security and egress controls. In particular, the code that calls node-fetch is outside the sandbox.

We haven’t yet created the ability for the FormData class from form-data to be passed from within the sandbox to outside of the sandbox to node-fetch, which it seems from my investigation is what is required to use the multipart/form-data APIs.

I’ve created a ticket in my team’s backlog for Forge to support using multipart/form-data APIs. We will get around to implementing that soon. If you are able to provide more information about your use case, it would help us to appropriately prioritise the work and make sure we enable you to achieve your use case!

1 Like

My use case for multipart/form-data is to copy attachments which is part of an application I’m creating to help share information across linked inssues which include recent comments and attachments. Thanks for informing me! Hopefully the API can be supported by Forge soon.

Thank you, I’ve added your request to a public tracking ticket https://ecosystem.atlassian.net/browse/FRGE-114.

1 Like

Hi @AlexFang it is a cross-post and for Confluence. But I think you can use it slightly adapted for jira as well.