Missed Team ’24? Catch up on announcements here.

×
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

How to POST attachment to Confluence page using REST API with perl?

Helen OBoyle January 11, 2016

I am trying to send file1.jpg to Confluence as an attachment to a page with ID 44073843, via perl's REST::Client module, using an existing, known good, $client connection that has already been successfully used to perform a GET of that page, immediately before this POST request.

The code I'm using to do that is:

$headers = {
    Accept => 'application/json',
    Authorization => 'Basic ' . encode_base64($user . ':' . $password),
    'X-Atlassian-Token' => 'no-check',
    'Content-Type' => 'form-data',
    Content =>
        [ file => ["file1.jpg"], ]};
$r = $client->POST('rest/api/content/44073843/child/attachment', $headers);

$client->responseCode() after execution of the POST is 500.

This was my best attempt at replicating in perl, the following curl example cited in Atlassian documentation:

curl -v -S -u admin:admin -X POST -H "X-Atlassian-Token: no-check" -F "file=@myfile.txt" -F "comment=this is my file" "http://localhost:8080/confluence/rest/api/content/3604482/child/attachment" | python -mjson.tool

The above curl command, when run with 'file1.jpg' in place of 'myfile.txt', and the appropriate URI for our local installation, does indeed upload attachments to the specified page.  There's just something in how I'm trying to use perl to create a multi-part form post that's not working, but I don't know what it is.  Is curl magically inserting some header for me that perl doesn't insert unless I explicitly add it to the headers list? Is my Content-Type or Content specification not what Confluence is expecting? I removed the comment field, as the API docs say that it's optional.  And, of course, I suspect that what I've done above doesn't actually include the file's contents, just its name, so I want to know how to send the file's contents, as well.  Can I just slurp the file into a string and pass that string?  Do I have to specify a header that says that I'm sending binary data?  I've never had to deal with a multipart form before, so I'm not sure that I'm doing it correctly.

Note:  I also tried a content type of 'multipart/form-data', and got the same results.

As a last ditch effort, I wanted to try to replicate what happens when I interactively upload an attachment, but in Confluence 5.8 (the version we are using), the upload attachment functionality appears to use the old prototype REST API, so merely creating a message that looks like the one that sends, isn't what I want to be doing.

After 24 hours, my post to stackoverflow hasn't gotten any replies, either.

Any thoughts?

1 answer

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

1 vote
Answer accepted
Scott Selberg
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 13, 2016

I was doing something simliar in perl,  here was my code that worked:

 

$response = $self->browser()->request( POST $self->confluenceUrl."/rest/api/content/$pageId/child/attachment",
                                             'Content_Type' => 'form-data',
                                             'Content'      => [ 'file' => [$attachment] ],
                                             'X-Atlassian-Token' => 'no-check',
                                             'Authorization' =>  'Basic ' . $self->credentials );

It does look like I used "Content_Type" rather than "Content-Type" as the key.

Helen OBoyle January 13, 2016

Scott, this looks interesting, and if you got it to work, I'm very curious! Were you using REST::Client, or some other package? Not sure I recognize it...

Scott Selberg
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 14, 2016

Hi, So, my approach was to create a "Confluence" object/module where I wrapped all of the syntax needed. The modules I'm using to make it all work are JSON, MIME::Base64, Rest::Client, LWP::UserAgent, HTTP::Request::Common. At the time, I was porting a TWiki web into Confluence. I was also using a custom rest interface to set the author and creation date as the default REST interface did not allow that. If you want more details send me an email at scott_selberg@keysight.com and I'll share the code with you.

Scott Selberg
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 19, 2016

Hi Helen,  thanks for your private email.  I decided perhaps the best way to get started was to post the full example code to BitBucket, so I did: https://bitbucket.org/selberg/confluence-rest-example-from-perl

Take a look at the code there and see if it helps you to get over your hurdle.  One of the things that I did was use Rest::Client to interact with Confluence for everything except uploading attachments.  For uploading attachments, I dropped back to LWP.

-Scott

Helen OBoyle January 20, 2016

Scott, thanks for the bigger picture.

It turns out that I didn't have my headers array structured properly for the LWP POST call – resulting in it not getting the proper content type to know it was a multi-part form, resulting in the server rejecting the request with a 415 error.  The moral of the story is that if you're getting a 415 error, you really ARE doing something wrong with your Content-Type, even if you're certain that you're not.

If you're having trouble getting this to work, definitely have a look at the code Scott posted.

TAGS
AUG Leaders

Atlassian Community Events