| owner | approved | decision | choice |
|---|---|---|---|
TBD |
TBD |
Approved |
Centralized API Client with Backoff |
| Item | Description |
|---|---|
| Status | Completed |
| Owner | TBD |
| Approved | TBD |
| Due Date | Completed |
| Decision | Yes |
Need a reliable way to interact with Confluence's REST API that handles:
- Rate limiting and backoff
- Authentication
- Pagination
- Error handling
- Response parsing
-
Confluence API Characteristics:
- Uses REST architecture
- Rate limits with 429 responses
- Supports pagination via _links
- Requires Bearer token auth
- Returns JSON responses
-
Common Challenges:
- Rate limiting during bulk operations
- Large response sets requiring pagination
- Network failures requiring retries
- Complex nested data structures
A centralized API client with:
- Exponential backoff for rate limits
- Automatic retry mechanism
- Pagination handling
- Type-safe response parsing
| Option 1: Axios Client | Option 2: Native Fetch | |
|---|---|---|
| Overview | Third-party HTTP client | Browser-standard API |
| Benefits | - Built-in retry - Interceptors - Wide adoption |
- No dependencies - Modern API - Native ESM support |
| Risks | - Extra dependency - Bundle size - ESM issues |
- Manual retry logic - Less middleware options |
| Decision | Status | Next Steps |
|---|---|---|
| Use Fetch | Completed |
- Add response type validation - Improve error handling |
| Backoff Strategy | Completed |
- Fine-tune retry delays - Add jitter |
| Response Types | Completed |
- Document all response types - Add runtime validation |
Key implementation files:
- utils/index.js - API client implementation
- scripts/all-spaces.js - Space API usage
- scripts/all-space-content.js - Content API usage
API Integration Patterns:
-
Backoff Implementation:
export async function fetchWithBackoff( url, retries = 5, initialDelay = 1000, ) { let currentDelay = initialDelay; for (let i = 0; i < retries; i++) { try { const response = await fetch(url); if (response.status === 429) { await new Promise((resolve) => setTimeout(resolve, currentDelay)); currentDelay *= 2; continue; } return await response.json(); } catch (error) { if (i === retries - 1) throw error; } } }
-
Type Definitions:
/** * @typedef {Object} ConfluenceSpace * @property {string} key - Space key * @property {string} name - Display name * @property {Object} homePage - Home page info */
-
Pagination Handling:
async function getAllContent(spaceKey) { let pages = []; let url = `/space/${spaceKey}/content`; while (url) { const data = await fetchWithBackoff(url); pages.push(...data.results); url = data._links?.next || null; } return pages; }