Confluence REST API for reading and updating wiki pages

In previous posts I wrote how to automate the work with Atlassian Jira, including automated ticket labeling. Now let’s try to use REST API of another popular Atlassian product – Confluence wiki engine.

Confluence REST API

What you may want to automate in Confluence? Obviously, it may be useful to read the pages that your colleagues regularly update and then use this data in some scripts as an input. You may also want to update your own Confluence pages, for example to post Vulnerability Scanning results. πŸ˜‰

Reading pages

You can read the page by Id using this function:

import json

def get_page_json(page_id, expand = False):
    if expand:
        suffix = "?expand=" + expand 
                              #body.storage
    else:
        suffix = ""

    url="https://confluence.corporation.com/rest/api/content/" + page_id + suffix
    response = requests.get(url, auth=(user, password))
    response.encoding = "utf8"
    return json.loads(response.text)
    
print(get_page_json("287346883", "body.storage"))

Output:

{u'status': u'current', u'body': {u'_expandable': {u'export_view': u'', u'styled_view': u'', u'editor': u'', u'anonymous_export_view': u'', u'view': u''}, u'storage': {u'_expandable': {u'content': u'/rest/api/content/287346883'}, u'representation': u'storage', u'value': u'<p>Test content</p>'}}, u'title': u'Test page', u'_expandable': {u'operations': u'', u'ancestors': u'', u'container': u'/rest/api/space/INFO', u'descendants': u'/rest/api/content/287346883/descendant', u'space': u'/rest/api/space/INFO', u'version': u'', u'metadata': u'', u'children': u'/rest/api/content/287346883/child', u'history': u'/rest/api/content/287346883/history'}, u'extensions': {u'position': u'none'}, u'_links': {u'self': u'https://confluence.corporation.com/rest/api/content/287346883', u'collection': u'/rest/api/content', u'tinyui': u'/x/-QWIE', u'base': u'https://confluence.corporation.com', u'webui': u'/display/INFO/Test+page', u'context': u''}, u'type': u'page', u'id': u'287346883'}

Without “?expand=body.storage” Confluence will return detailed information about the version, but will not return the full content of the page toΒ body -> storage -> value. πŸ˜‰

As you can see, JSON data is very convenient. You can easily read the title and html content:

print(json_data['title'])
print(json_data['body']['storage']['value'])

Output:

Test page
<p>Test content</p>

Editing

OK. How can we change the content of this page? We need to send some minimal JSON to the Confluence API, for example using this function:

def set_page_json(page_id,json_content):
    headers = {
        'Content-Type': 'application/json',
    }

    response = requests.put("https://confluence.corporation.com/rest/api/content/" + page_id, headers=headers, data=json.dumps(json_content),
                 auth=(user, password))
    return(response.text)

What should be the structure of this JSON?

I cook it this way:

json_data = functions_confluence.get_page_json("277387103")

new_json_data = dict()
new_json_data['id'] = json_data['id']
new_json_data['type'] = json_data['type']
new_json_data['title'] = json_data['title']
new_json_data['type'] = json_data['type']
new_json_data['version'] = {"number": json_data['version']['number'] + 1}
if not 'key' in json_data:
    new_json_data['key'] = json_data['space']['key']
else:
    new_json_data['key'] = json_data['key']

new_json_data['body'] = {'storage':{'value':'<p>This is the updated text for the new page</p>','representation':'storage'}}

There should be something like this in new_json_data:

{'body': {'storage': {'representation': 'storage', 'value': '<p>This is the updated text for the new page</p>'}}, 'title': u'Test page', 'version': {'number': 2}, 'key': u'INFO', 'type': u'page', 'id': u'277387103'}

The response after sending JSON will be:

{"id":"277387103","type":"page","status":"current","title":"Test page", ....

And the content of the page should change.

Tables

What if we try to add a table?

new_json_data['body'] = {'storage':{'value':'<p><table><tr><th>head1</th><th>head2</th></tr><tr><td>value1</td><td>value2</td></tr><tr><td>value3</td><td>value4</td></tr></table></p>','representation':'storage'}}

Confluence table example

It’s simple!

Images and other attacments

Unfortunately, it’s not possible to send a picture in base64 this way =(

What if I attach a file to a page and use a link to it in code? It’s possible.

I’m uploading the file using this function:

def attach_file_to_page(page_id, filepath, filename):

    headers = {
        'X-Atlassian-Token': 'no-check',
    }

    files = {
        'file': (filename, open(filepath, 'rb')),
    }

    #delete attach with the same name
    response = requests.get("https://confluence.corporation.com/rest/api/content/" + page_id + "/child/attachment", auth=(user, password))
    for attachment in json.loads(response.text)['results']:
        if attachment['title'] == filename:
            requests.delete("https://confluence.corporation.com/rest/api/content/" + attachment['id'], headers=headers, auth=(user, password))

    #attack files
    response = requests.post("https://confluence.corporation.com/rest/api/content/" +page_id+ "/child/attachment", headers=headers, files=files,
                     auth=(user, password))
    return(response.text)

Note that before you upload a file, you need to verify that the file with such name is not attached already or you will get an error. So I check all the attached files and delete files with the specified name.

URL of the file will be https://confluence.corporation.com/download/attachments/277387103/test.jpg and we can use it in code:

functions_confluence.attach_file_to_page("277387103", "data/test.jpg", "test.jpg")
img_url = "https://confluence.corporation.com/download/attachments/277387103/test.jpg"

new_json_data['body'] = {'storage':{'value': '<img src="'+img_url+'"></img>','representation':'storage'}}

Output:
{"id":"277387103","type":"page","status":"current","title":"Test page", ...

And test.jpg</ code> will appear on the page:

Confluence image attached

Useful curl one-liners you can also find on the official website here: https://developer.atlassian.com/server/confluence/confluence-rest-api-examples/

Leave a Reply

Your email address will not be published. Required fields are marked *