Claude-skill-registry cloudflare-api-orchestration
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/cloudflare-api-orchestration" ~/.claude/skills/majiayu000-claude-skill-registry-cloudflare-api-orchestration && rm -rf "$T"
skills/data/cloudflare-api-orchestration/SKILL.mdCloudflare API Orchestration Skill
This skill enforces BooksTrack-specific API orchestration patterns for Cloudflare Workers.
Core Principles
1. Provider Orchestration (MANDATORY)
NEVER make direct API calls without orchestration layer.
Correct pattern:
// orchestrator.js export class APIOrchestrator { async searchBooks(query, options = {}) { const providers = [ { name: 'google', fn: () => this.googleBooks.search(query) }, { name: 'openlibrary', fn: () => this.openLibrary.search(query) } ]; for (const provider of providers) { try { const result = await provider.fn(); return { ...result, provider: `orchestrated:${providers.map(p => p.name).join('+')}`, cached: false }; } catch (error) { console.warn(`Provider ${provider.name} failed:`, error); continue; } } // Final fallback to cache const cached = await this.kv.get(`book:${query}`); if (cached) { return { ...JSON.parse(cached), provider: 'cache:kv', cached: true }; } throw new Error('All providers failed'); } }
Wrong pattern (FORBIDDEN):
// ❌ Direct API call without orchestration async function searchBooks(query) { const response = await fetch(`https://www.googleapis.com/books/v1/volumes?q=${query}`); return response.json(); // Missing provider tag, no fallback, no caching }
2. Provider Tagging (REQUIRED)
All responses MUST include provider metadata:
{ data: { /* actual response */ }, provider: "orchestrated:google+openlibrary", // Multi-provider cached: false, timestamp: Date.now() }
Tag formats:
- Successful multi-provider aggregation"orchestrated:google+openlibrary"
- Single provider (fallback failed or only one available)"google"
- Retrieved from KV cache"cache:kv"
- Retrieved from D1 database"cache:d1"
3. Error Handling Patterns
Implement graceful degradation:
try { // Primary provider const result = await primaryProvider.fetch(); return { data: result, provider: 'primary', cached: false }; } catch (primaryError) { console.warn('Primary provider failed:', primaryError); try { // Secondary provider const result = await secondaryProvider.fetch(); return { data: result, provider: 'secondary', cached: false }; } catch (secondaryError) { console.warn('Secondary provider failed:', secondaryError); // Cache fallback const cached = await cache.get(key); if (cached) { return { data: cached, provider: 'cache:kv', cached: true }; } // Final error with context throw new APIError('All providers exhausted', { primaryError, secondaryError, key }); } }
4. D1 Query Patterns
Always use prepared statements:
// ✅ Correct - prepared statement const result = await env.DB.prepare( 'SELECT * FROM books WHERE isbn = ?' ).bind(isbn).first(); // ❌ Wrong - SQL injection vulnerability const result = await env.DB.prepare( `SELECT * FROM books WHERE isbn = '${isbn}'` ).first();
Batch operations for efficiency:
// ✅ Correct - batch insert const stmt = env.DB.prepare('INSERT INTO books (isbn, title) VALUES (?, ?)'); const batch = books.map(book => stmt.bind(book.isbn, book.title)); await env.DB.batch(batch); // ❌ Wrong - individual inserts (slow) for (const book of books) { await env.DB.prepare('INSERT INTO books (isbn, title) VALUES (?, ?)') .bind(book.isbn, book.title) .run(); }
5. KV Caching Strategy
Key naming convention:
namespace:entity:id
Examples:
book:isbn:9780134685991search:query:swift+programminguser:profile:user123
Caching pattern:
async function getCachedOrFetch(key, fetchFn, ttl = 3600) { // Try cache first const cached = await env.KV.get(key, { type: 'json' }); if (cached) { return { ...cached, cached: true }; } // Fetch from provider const fresh = await fetchFn(); // Cache for TTL seconds await env.KV.put(key, JSON.stringify(fresh), { expirationTtl: ttl, metadata: { cached_at: Date.now() } }); return { ...fresh, cached: false }; }
6. Rate Limiting
Implement per-endpoint rate limits:
import { RateLimiter } from './rate-limiter'; const limiter = new RateLimiter({ search: { requests: 100, window: 60 }, // 100 req/min details: { requests: 200, window: 60 } // 200 req/min }); async function handleSearch(request, env) { const clientId = request.headers.get('CF-Connecting-IP'); if (!await limiter.check('search', clientId)) { return new Response('Rate limit exceeded', { status: 429, headers: { 'Retry-After': '60', 'X-RateLimit-Limit': '100', 'X-RateLimit-Remaining': '0' } }); } // Process request... }
7. Circuit Breaker Pattern
Prevent cascading failures:
class CircuitBreaker { constructor(threshold = 5, timeout = 60000) { this.failureCount = 0; this.threshold = threshold; this.timeout = timeout; this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN this.nextAttempt = Date.now(); } async call(fn) { if (this.state === 'OPEN') { if (Date.now() < this.nextAttempt) { throw new Error('Circuit breaker OPEN'); } this.state = 'HALF_OPEN'; } try { const result = await fn(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failureCount = 0; this.state = 'CLOSED'; } onFailure() { this.failureCount++; if (this.failureCount >= this.threshold) { this.state = 'OPEN'; this.nextAttempt = Date.now() + this.timeout; } } }
BooksTrack-Specific Patterns
Book Search API
// Route: GET /api/v2/books/search?q=... export async function handleBookSearch(request, env) { const url = new URL(request.url); const query = url.searchParams.get('q'); if (!query) { return new Response(JSON.stringify({ error: 'Missing query parameter' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } const orchestrator = new APIOrchestrator(env); try { const result = await orchestrator.searchBooks(query); return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'public, max-age=3600', 'X-Provider': result.provider } }); } catch (error) { console.error('Search failed:', error); return new Response(JSON.stringify({ error: 'Search failed', message: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } }
Book Details API
// Route: GET /api/v2/books/:isbn export async function handleBookDetails(isbn, env) { // Try D1 first (authoritative source) const cached = await env.DB.prepare( 'SELECT * FROM books WHERE isbn = ?' ).bind(isbn).first(); if (cached) { return { ...cached, provider: 'cache:d1', cached: true }; } // Fetch from providers const orchestrator = new APIOrchestrator(env); const result = await orchestrator.getBookByISBN(isbn); // Store in D1 for future requests await env.DB.prepare( 'INSERT OR REPLACE INTO books (isbn, title, author, data) VALUES (?, ?, ?, ?)' ).bind(isbn, result.title, result.author, JSON.stringify(result)).run(); return result; }
Anti-Patterns to Avoid
❌ Direct API Calls
// DON'T DO THIS const response = await fetch('https://api.example.com/books');
❌ Missing Provider Tags
// DON'T DO THIS return { data: books }; // Missing provider metadata
❌ Unhandled Errors
// DON'T DO THIS const result = await provider.fetch(); // No try-catch
❌ SQL Injection Vulnerabilities
// DON'T DO THIS await env.DB.prepare(`SELECT * FROM books WHERE title = '${title}'`).first();
❌ No Caching Strategy
// DON'T DO THIS - always hitting live APIs const result = await provider.fetch(); // No cache check
Validation Checklist
When implementing or reviewing Cloudflare Workers APIs, verify:
- All API calls go through orchestration layer
- Responses include provider tags
- Fallback chains implemented (primary → secondary → cache)
- D1 queries use prepared statements
- KV keys follow naming convention
- Rate limiting configured for public endpoints
- Circuit breakers protect external services
- Error handling provides useful context
- Caching strategy reduces API calls
- Logging captures provider failures
Integration with Code Review
This skill complements the
code-review-grok subagent. When code review identifies orchestration violations, this skill provides the correct patterns to follow.
Async API Development (v2.0.64)
Complex API implementations can run in background:
// Launch complex endpoint implementation in background Task({ subagent_type: "cloudflare-specialist", prompt: "Implement /api/v3/books/search with full orchestration, caching, rate limiting", run_in_background: true }) // Continue with other work (UI, tests)... // Retrieve implementation when ready TaskOutput({ task_id: "agent_xyz123", block: true })
Background-friendly tasks:
- Complex multi-provider orchestration
- D1 schema migrations
- KV→D1 data migrations
- Comprehensive API security audits
Recommended Option Pattern (v2.0.62):
When presenting API implementation choices:
options: [ {label: "Orchestrated (Recommended)", description: "Multi-provider with fallback"}, {label: "Single provider", description: "Google Books only"}, {label: "Cache-first", description: "D1/KV with lazy provider fetch"} ]
Last Updated: December 11, 2025 Maintained by: Claude Code PM System Related Agents: cloudflare-specialist, code-review-grok Claude Code Version: v2.0.65