G’day,
I’m having problems creating/updating pages in Confluence through the REST v2 API, more specifically an INVALID_MESSAGE error. I’m working on an app which does encryption on a per-page basis, so I want to run some code every time a page is updated/created to ensure any new content is encrypted. I’ve got an event trigger hooked up which catches any of the page creation/modification events - this part seems to work.
What doesn’t work is updating pages (or creating new ones) from the app - no matter what I try, I can’t seem to get any sensible response beyond “INVALID_MESSAGE” and a 400 status code. I’ve got the write:page:confluence permission
in my manifest, as instructed by the API documentation, and as far as I can tell, the argument to the call looks like the example code. The ID is present in the path and the request body has that same ID plus a title, status, version (+1 from the previous version), and body (as a string, not an object).
Below is a minimal test app that reproduces the issue. It will attempt to run when a page containing the magic string !update
is saved. Attempting to create a new page also fails in the same way, so I assume that there’s some small thing I’m missing with both. The manifest contains a bunch of scopes - {read,write,delete}:page:confluence, read:confluence-content.{summary,all}, write:confluence-content
but I think only the read/write:page:confluence
ones are necessary for this example.
import api, { route } from '@forge/api';
export async function run(event, context) {
console.log(`Event ${event.eventType} on page '${event.content?.title}'`)
const pageId = event.content.id;
const pageContents = await getPageContents(pageId);
const version = pageContents.version?.number;
const body = pageContents.body?.atlas_doc_format?.value;
const newTitle = pageContents.title.endsWith(" For Dummies") ? pageContents.title : pageContents.title + " For Dummies";
const newBody = body.replace("!update", ""); // Don't want an infinite loop!
if (body.includes("!update")) {
console.log("Performing update...");
const result = await updatePage(pageId, newTitle, version + 1, newBody);
console.log("Update result:", result);
}
}
const getPageContents = async (pageId) => {
try {
const response = await api.asApp().requestConfluence(route`/wiki/api/v2/pages/${pageId}?body-format=atlas_doc_format`, {
headers: {
"Accept": "application/json",
}
});
if (response.ok) {
return await response.json();
} else {
console.error("Unexpected response status in getPageContents(): ", response.status, response.statusText);
console.error(await response.json());
return {};
}
} catch (err) {
console.error("Error loading page contents:", err)
}
}
const updatePage = async (pageId, title, version, contents) => {
try {
const args = {
"method": "PUT",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"id": pageId,
"status": "current",
"title": title,
"version": {
"number": version,
"message": "MODIFIED"
},
"body": {
"representation": "atlas_doc_format",
"value": contents
}
}
};
console.log(`Calling /wiki/api/v2/pages/${pageId} with args ${JSON.stringify(args)}`)
const response = await api.asApp().requestConfluence(route`/wiki/api/v2/pages/${pageId}`, args);
if (response.ok) {
return await response.json();
} else {
console.error("Unexpected response status in updatePage(): ", response.status, response.statusText);
console.error(await response.json());
return {};
}
} catch (err) {
console.error("Error updating page:", err)
}
}
I have had luck with DELETE, and while I will eventually need to use that method, it’s not helpful by itself.
Hoping I’ve made a silly mistake somewhere that’ll be an easy fix