用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Hack23/cia --skill api-integration命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Identity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3
Business continuity and disaster recovery: 30-day retention, quarterly restore tests, RTO/RPO targets per ISO 27001 A.17
Political psychology, cognitive biases, group dynamics, leadership analysis, decision-making patterns for Swedish political intelligence
基于 SOC 职业分类
正在显示 SKILL.md
| name | api-integration |
| description | External API integration patterns, retry logic, circuit breakers, caching, rate limiting for government data APIs |
| license | Apache-2.0 |
Provide robust patterns for integrating the CIA platform with external government data APIs, including the Swedish Riksdagen, Election Authority, World Bank, and ESV (Swedish Financial Management Authority). Covers resilience, caching, and error handling.
Do NOT use for:
| API | Base URL | Data Type | Rate Limit |
|---|---|---|---|
| Riksdagen Open Data | data.riksdagen.se | Parliament data, votes, documents | Best effort |
| Swedish Election Authority | data.val.se | Election results, parties | Low volume |
| World Bank Open Data | api.worldbank.org | Economic indicators | 50 req/sec |
| ESV | www.esv.se | Government finances | Best effort |
@Service
public class ResilientApiClient {
private static final int MAX_RETRIES = 3;
private static final long BASE_DELAY_MS = 1000;
private static final Logger LOG = LoggerFactory.getLogger(ResilientApiClient.class);
public <T> T executeWithRetry(Supplier<T> apiCall, String operationName) {
int attempt = 0;
while (true) {
try {
return apiCall.get();
} catch (Exception e) {
attempt++;
if (attempt >= MAX_RETRIES || !isRetryable(e)) {
LOG.error("API call failed after {} attempts: {}", attempt, operationName, e);
throw new ApiIntegrationException(operationName, e);
}
long delay = calculateBackoff(attempt);
LOG.warn("Retry {}/{} for {} after {}ms", attempt, MAX_RETRIES, operationName, delay);
try {
Thread.sleep(delay);
} (InterruptedException ie) {
Thread.currentThread().interrupt();
(operationName, ie);
}
}
}
}
{
BASE_DELAY_MS * ( << (attempt - ));
ThreadLocalRandom.current().nextLong(, exponentialDelay / );
Math.min(exponentialDelay + jitter, );
}
{
(e HttpClientErrorException httpErr) {
httpErr.getStatusCode().value();
status == || status >= ;
}
e ResourceAccessException
|| e SocketTimeoutException;
}
}
@Component
public class CircuitBreaker {
private enum State { CLOSED, OPEN, HALF_OPEN }
private State state = State.CLOSED;
private int failureCount = 0;
private long lastFailureTime = 0;
private static final int FAILURE_THRESHOLD = 5;
private static final long RECOVERY_TIMEOUT_MS = 60_000;
public synchronized <T> T execute(Supplier<T> action, Supplier<T> fallback) {
if (state == State.OPEN) {
if (System.currentTimeMillis() - lastFailureTime > RECOVERY_TIMEOUT_MS) {
state = State.HALF_OPEN;
} else {
return fallback.get();
}
}
try {
T result = action.get();
reset();
return result;
} catch (Exception e) {
recordFailure();
fallback.get();
}
}
{
failureCount++;
lastFailureTime = System.currentTimeMillis();
(failureCount >= FAILURE_THRESHOLD) {
state = State.OPEN;
}
}
{
failureCount = ;
state = State.CLOSED;
}
}
@Configuration
@EnableCaching
public class ApiCacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(Duration.ofHours(1))
.recordStats());
return manager;
}
}
@Service
public class RiksdagDataService {
@Cacheable(value = "politicians", key = "#personId")
public PoliticianData getPolitician(String personId) {
return riksdagClient.fetchPerson(personId);
}
@CacheEvict(value = "politicians", allEntries = true)
@Scheduled(cron = "0 0 2 * * *") // Refresh at 2 AM daily
public void evictPoliticianCache() {
LOG.info("Evicting politician cache for daily refresh");
}
}
| Data Type | TTL | Reason |
|---|---|---|
| Politician profiles | 24 hours | Changes infrequently |
| Voting records | 1 hour | Updated during sessions |
| Document content | 7 days | Immutable once published |
| Election results | 30 days | Updated only at elections |
| Economic indicators | 24 hours | Daily updates from World Bank |
@Component
public class RateLimiter {
private final Semaphore semaphore;
private final ScheduledExecutorService scheduler;
public RateLimiter(@Value("${api.rate.limit:10}") int maxRequestsPerSecond) {
this.semaphore = new Semaphore(maxRequestsPerSecond);
this.scheduler = Executors.newSingleThreadScheduledExecutor();
this.scheduler.scheduleAtFixedRate(
() -> semaphore.release(maxRequestsPerSecond - semaphore.availablePermits()),
1, 1, TimeUnit.SECONDS
);
}
public <T> T throttled(Supplier<T> apiCall) throws InterruptedException {
semaphore.acquire();
return apiCall.get();
}
}
public class ApiIntegrationException extends RuntimeException {
private final String operationName;
private final int httpStatus;
public ApiIntegrationException(String operationName, Throwable cause) {
super("API integration failed: " + operationName, cause);
this.operationName = operationName;
this.httpStatus = extractStatus(cause);
}
}
| Control | Requirement |
|---|---|
| ISO 27001 A.8.24 | Use of cryptography for API transport |
| NIST CSF PR.DS-2 | Data-in-transit protection |
| CIS Control 12 | Network infrastructure management |