Integrate Open API (Swagger) — Confluence Cloud MacroNew
This Confluence user macro dynamically loads and renders an OpenAPI (Swagger) specification using Swagger UI.
The macro retrieves the specification URL from macro parameters, validates its availability and JSON structure, and initializes SwaggerUIBundle with deep linking and persistent authorization enabled. It includes loading states with AUI spinner feedback, graceful error handling for missing or invalid specifications, and custom dark-mode styling aligned with Atlassian design tokens to ensure seamless integration with Confluence themes.
Template
<script>
window.AP.theming.initializeTheming();
</script>
#set ($!swaggerUrl = $parameters["url"])
<link
rel="stylesheet"
href="https://unpkg.com/swagger-ui-dist/swagger-ui.css"
/>
<style>
html[data-color-mode="dark"] .swagger-ui .scheme-container,
html[data-color-mode="dark"] #servers {
background: #1c1c21;
}
html[data-color-mode="dark"] .swagger-ui .checkbox p,
html[data-color-mode="dark"] .swagger-ui .dialog-ux .modal-ux-content h4,
html[data-color-mode="dark"] .swagger-ui .dialog-ux .modal-ux-content p,
html[data-color-mode="dark"] .swagger-ui .dialog-ux .modal-ux-header h3,
html[data-color-mode="dark"] .swagger-ui .errors-wrapper .errors h4,
html[data-color-mode="dark"] .swagger-ui .errors-wrapper hgroup h4,
html[data-color-mode="dark"] .swagger-ui .info .base-url,
html[data-color-mode="dark"] .swagger-ui .info .title,
html[data-color-mode="dark"] .swagger-ui .info h1,
html[data-color-mode="dark"] .swagger-ui .info h2,
html[data-color-mode="dark"] .swagger-ui .info h3,
html[data-color-mode="dark"] .swagger-ui .info h4,
html[data-color-mode="dark"] .swagger-ui .info h5,
html[data-color-mode="dark"] .swagger-ui .info li,
html[data-color-mode="dark"] .swagger-ui .info p,
html[data-color-mode="dark"] .swagger-ui .info table,
html[data-color-mode="dark"] .swagger-ui .loading-container .loading::after,
html[data-color-mode="dark"] .swagger-ui .model,
html[data-color-mode="dark"] .swagger-ui .opblock .opblock-section-header h4,
html[data-color-mode="dark"] .swagger-ui .opblock .opblock-section-header > label,
html[data-color-mode="dark"] .swagger-ui .opblock .opblock-summary-description,
html[data-color-mode="dark"] .swagger-ui .opblock .opblock-summary-operation-id,
html[data-color-mode="dark"] .swagger-ui .opblock .opblock-summary-path,
html[data-color-mode="dark"]
.swagger-ui
.opblock
.opblock-summary-path__deprecated,
html[data-color-mode="dark"] .swagger-ui .opblock-description-wrapper,
html[data-color-mode="dark"] .swagger-ui .opblock-description-wrapper h4,
html[data-color-mode="dark"] .swagger-ui .opblock-description-wrapper p,
html[data-color-mode="dark"] .swagger-ui .opblock-external-docs-wrapper,
html[data-color-mode="dark"] .swagger-ui .opblock-external-docs-wrapper h4,
html[data-color-mode="dark"] .swagger-ui .opblock-external-docs-wrapper p,
html[data-color-mode="dark"] .swagger-ui .opblock-tag small,
html[data-color-mode="dark"] .swagger-ui .opblock-title_normal,
html[data-color-mode="dark"] .swagger-ui .opblock-title_normal h4,
html[data-color-mode="dark"] .swagger-ui .opblock-title_normal p,
html[data-color-mode="dark"] .swagger-ui .parameter__name,
html[data-color-mode="dark"] .swagger-ui .parameter__type,
html[data-color-mode="dark"] .swagger-ui .response-col_links,
html[data-color-mode="dark"] .swagger-ui .response-col_status,
html[data-color-mode="dark"] .swagger-ui .responses-inner h4,
html[data-color-mode="dark"] .swagger-ui .responses-inner h5,
html[data-color-mode="dark"] .swagger-ui .scheme-container .schemes > label,
html[data-color-mode="dark"] .swagger-ui .scopes h2,
html[data-color-mode="dark"] .swagger-ui .servers > label,
html[data-color-mode="dark"] .swagger-ui .tab li,
html[data-color-mode="dark"] .swagger-ui label,
html[data-color-mode="dark"] .swagger-ui select,
html[data-color-mode="dark"] .swagger-ui table.headers td {
color: var(--ds-text);
}
.swagger-status {
border: 1px solid #dfe1e6;
border-radius: 6px;
background: #f7f8f9;
padding: 10px;
display: flex;
align-items: center;
gap: 8px;
}
#swagger-ui-container {
display: none;
border: 1px solid #dfe1e6;
border-radius: 6px;
}
</style>
<div id="swagger-status">
<aui-spinner size="small"></aui-spinner>
<div class="aui-message aui-message-info">
<p class="title">
<strong>Loading OpenAPI specification…</strong>
</p>
</div>
</div>
<div id="swagger-ui-container"></div>
<div id="swagger-error-container"></div>
<div id="swagger-data" data-url="$swaggerUrl"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
(() => {
const ready = (fn) => {
if (document.readyState !== "loading") {
fn();
} else {
document.addEventListener("DOMContentLoaded", fn);
}
};
ready(async () => {
const status = document.getElementById("swagger-status");
const container = document.getElementById("swagger-ui-container");
const errorContainer = document.getElementById(
"swagger-error-container"
);
const swaggerUrl = document
.getElementById("swagger-data")
.dataset.url.trim();
const renderError = (message) => {
status.style.display = "none";
errorContainer.innerHTML = `
<div
role="note"
aria-labelledby="swagger-error-title"
class="aui-message aui-message-error"
>
<p id="swagger-error-title" aria-hidden="true" class="title">
<strong hidden>Error: </strong>
<strong>Could not reach URL</strong>
</p>
<p>
No OpenAPI / Swagger JSON found at this link.<br/>
Please verify that the URL points directly to a valid
OpenAPI / Swagger JSON file.
</p>
</div>
`;
};
try {
if (!swaggerUrl) {
renderError("Missing specification URL.");
return;
}
const res = await fetch(swaggerUrl);
if (!res.ok) {
renderError("HTTP " + res.status + " returned.");
return;
}
const text = await res.text();
try {
JSON.parse(text);
} catch {
renderError("Invalid JSON document.");
return;
}
status.style.display = "none";
container.style.display = "block";
SwaggerUIBundle({
url: swaggerUrl,
dom_id: "#swagger-ui-container",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset,
],
layout: "BaseLayout",
persistAuthorization: true,
});
} catch (err) {
renderError();
}
});
})();
</script>User Parameters
URL
Enter a URL to fetch data from
You May Also Like
Generate a list of all the content created by a current user by default or a specified user across your Confluence site.
Based on CQL it shows a table with: Page title, Author, Updated, Status
Displays a list of pages in specific space with certain title or label
Use sticky previous/next buttons to navigate through your Confluence page tree in a linear reading order
Convert a specified amount of cryptocurrency to fiat currency.
Generate a list of labels from all spaces leading to corresponding content pages, organized in alphabetical order.
Find image within page attachments. Handy for reuse files and update them all at once
The content of this macro will not go to the printing page
An overview of all pages within one space which contains the title, the version, and the last updated date
List out a table to display the assignee history for Issues by JQL. Shows the following information: Issue Key, Summary, and Assignee history