Degraded performance Customers may experience intermittent errors using Community search. Our platform vendor is investigating.
It's not the same without you
Join the community to find out what other Atlassian users are discussing, debating and creating.
I would like to write content to an existing page using the REST API, here's my current script:
#!/usr/bin/python # # Reference: http://isbullsh.it/2012/06/Rest-api-in-python/ # import sys import getpass import json import requests BASE_URL = "http://confluence.XXXXXX.com/rest/api/content" PAGEID = 9470040 def main(): username = raw_input('login: ') passwd = getpass.getpass() url = "{base}/{pageid}".format( base = BASE_URL, pageid = PAGEID) data = json.dumps( { 'id' : '%d' % PAGEID, 'type' : 'page', 'title' : 'Sandbox', 'space' : {'key' : 'HSWc'}, 'body' : { 'storage' : { 'representation' : 'storage', 'value' : """ <table> <tbody> <tr> <th>Hello</th> <th>World</th> </tr> <tr> <td>Nick</td> <td>Rocks!</td> </tr> </tbody> </table> """ } } }) r = requests.put( url, data = data, auth = (username, passwd), headers = { 'Content-Type' : 'application/json', 'Accept' : 'application/json' } ) r.raise_for_status() if __name__ == "__main__" : main()
But I'm getting "requests.exceptions.HTTPError: 400 Client Error: Bad Request"
There currently isn't any working documentation for using the REST API. Please help!
I've now got a working example. The documentation does not specify all the required fields to make this work, but it does state that the next version number must be specified.
So root cause to my failure was not explicitly specifying the next version number.
After I corrected that, the newly modified page was orphaned (https://jira.atlassian.com/browse/CRA-487). But as sash pointed out, I found the same workaround. Below is my complete working example:
$ python write_page.py -h usage: write_page.py [-h] [-u USER] [-t TITLE] [-f FILE] pageid [html] positional arguments: pageid Specify the Conflunce page id to overwrite html Write the immediate html string to confluence page optional arguments: -h, --help show this help message and exit -u USER, --user USER Specify the username to log into Confluence -t TITLE, --title TITLE Specify a new title -f FILE, --file FILE Write the contents of FILE to the confluence page
import argparse import getpass import sys import json import keyring import requests #----------------------------------------------------------------------------- # Globals BASE_URL = "http://confluence.XXXXX.com/rest/api/content" VIEW_URL = "http://confluence.XXXXX.com/pages/viewpage.action?pageId=" def pprint(data): ''' Pretty prints json data. ''' print json.dumps( data, sort_keys = True, indent = 4, separators = (', ', ' : ')) def get_page_ancestors(auth, pageid): # Get basic page information plus the ancestors property url = '{base}/{pageid}?expand=ancestors'.format( base = BASE_URL, pageid = pageid) r = requests.get(url, auth = auth) r.raise_for_status() return r.json()['ancestors'] def get_page_info(auth, pageid): url = '{base}/{pageid}'.format( base = BASE_URL, pageid = pageid) r = requests.get(url, auth = auth) r.raise_for_status() return r.json() def write_data(auth, html, pageid, title = None): info = get_page_info(auth, pageid) ver = int(info['version']['number']) + 1 ancestors = get_page_ancestors(auth, pageid) anc = ancestors[-1] del anc['_links'] del anc['_expandable'] del anc['extensions'] if title is not None: info['title'] = title data = { 'id' : str(pageid), 'type' : 'page', 'title' : info['title'], 'version' : {'number' : ver}, 'ancestors' : [anc], 'body' : { 'storage' : { 'representation' : 'storage', 'value' : str(html), } } } data = json.dumps(data) url = '{base}/{pageid}'.format(base = BASE_URL, pageid = pageid) r = requests.put( url, data = data, auth = auth, headers = { 'Content-Type' : 'application/json' } ) r.raise_for_status() print "Wrote '%s' version %d" % (info['title'], ver) print "URL: %s%d" % (VIEW_URL, pageid) def get_login(username = None): ''' Get the password for username out of the keyring. ''' if username is None: username = getpass.getuser() passwd = keyring.get_password('confluence_script', username) if passwd is None: passwd = getpass.getpass() keyring.set_password('confluence_script', username, passwd) return (username, passwd) def main(): parser = argparse.ArgumentParser() parser.add_argument( "-u", "--user", default = getpass.getuser(), help = "Specify the username to log into Confluence") parser.add_argument( "-t", "--title", default = None, type = str, help = "Specify a new title") parser.add_argument( "-f", "--file", default = None, type = str, help = "Write the contents of FILE to the confluence page") parser.add_argument( "pageid", type = int, help = "Specify the Conflunce page id to overwrite") parser.add_argument( "html", type = str, default = None, nargs = '?', help = "Write the immediate html string to confluence page") options = parser.parse_args() auth = get_login(options.user) if options.html is not None and options.file is not None: raise RuntimeError( "Can't specify both a file and immediate html to write to page!") if options.html: html = options.html else: with open(options.file, 'r') as fd: html = fd.read() write_data(auth, html, options.pageid, options.title) if __name__ == "__main__" : main()
Thanks for posting this, which saved me a great deal of time. One thing to be careful of is if you are renaming the page by giving it a new title, then that title cannot be the same as the any of the titles in the space. REST API will return a 400 error if there's a name clash.
Hi Nick,
I am using your example. My code writes to the Confluence page only as text, I can't get Confluence to display it as a table. For example, I can write this:
<table><tbody><tr><th>a</th><th>b</th><th>c</th><th>d</th><th><p>e</p></th></tr><tr><td colspan="1">1</td><td colspan="1">2</td><td colspan="1">3</td><td colspan="1">4</td><td colspan="1">5</td></tr></tbody></table>
or I tried adding html elements to it, and it writes this:
<!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html>
If you are able to view this as a table, can you please tell me, what did you supply in the 'html' argument in your last example?
Thanks,
Dirce
Nick,
Thanks so much for posting this. It is very helpful. One thing I have found is that one html file may upload with no issues while a different html file throws a
400 Client Error: Bad Request for url: ....
I think it may have to do with any errors in the html, but I'm not sure about that. Have you run into this and do you have any solutions?
Thanks
-Dan
I should have said storage format, not html. But the problem is the same. If the storage format file has any bug at all, it won't upload. Maybe there is a way to validate the file locally?
May be you can try to convert it: https://developer.atlassian.com/cloud/confluence/rest/#api-contentbody-convert-to-post
Hey Nick,
did you happen to come across this documentation already?
Following the example curl-request to create a new page, you also have an example on how to update a page.
I hope this helps!
Regards,
Philipp
That's the only example I could find on the planet. When I tried it, I got a strange error complaining about the header. I'm not at work today so I can't paste in the error message. But that's the example I'm trying to imitate with the script. It doesn't work.
I see. Unfortunately I haven't messed with the API in a while and even then it was only JIRA and read-requests. Since the header is presented, it's strange that this would result in an error considering it matches the type of data provided. Yes, the ' are ' and are probably used for compatibility in case one decides to use single-quotes instead of quotes.
Take a look at the discussions here https://answers.atlassian.com/questions/312039
It looks like it the issue is related to missing ancestors in your json
"ancestors":[ { "id":"ID_OF_THE_PARENT_PAGE", "type":"page", "title":"TITLE OF THE PARENT PAGE" }],
Java example for quick ref https://bitbucket.org/jaysee00/confluence-rest-api-example/src/master/src/main/java/com/atlassian/api/examples/Main.java
This community is celebrating its one-year anniversary and Atlassian co-founder Mike Cannon-Brookes has all the feels.
Read moreHi Community! Kesha (kay-sha) from the Confluence marketing team here! Can you share stories with us on how your non-technical (think Marketing, Sales, HR, legal, etc.) teams are using Confluen...
Connect with like-minded Atlassian users at free events near you!
Find a groupConnect with like-minded Atlassian users at free events near you!
Unfortunately there are no AUG chapters near you at the moment.
Start an AUGYou're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.