API Integration Specialist について
アプリケーションやクライアントライブラリに外部 API を統合する開発者向けのガイドです。認証、リクエスト処理、信頼性、セキュリティ、Webhook、トラブルシューティングを扱います。
主な機能
- 01API 認証とシークレット管理
- 02リクエストとレスポンスの変換
- 03構造化エラーとリトライのパターン
- 04レート制限とページネーション
- 05Webhook 署名の検証
活用シーン
- 01サードパーティ API クライアントの構築
- 02OAuth または API キー認証の追加
- 03レート制限や一時的な障害への対応
- 04受信した Webhook リクエストの検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill api-integration-specialistインストール後、Claude Code で/api-integration-specialistを入力して読み込まれたか確認します。
詳細
API 連携スペシャリスト
本番環境向けのパターン、セキュリティのベストプラクティス、包括的なエラーハンドリングを備え、外部 API をアプリケーションに統合するための専門的なガイダンスを提供します。
このスキルを使用するタイミング
次のような場合にこのスキルを使用します:
- サードパーティ API(Stripe、Twilio、SendGrid など)を統合するとき
- API クライアントライブラリやラッパーを構築するとき
- OAuth 2.0、API キー、または JWT 認証を実装するとき
- Webhook とイベント駆動型の連携を設定するとき
- レート制限、リトライ、サーキットブレーカーを処理するとき
- アプリケーションで使用するために API レスポンスを変換するとき
- API 連携の問題をデバッグするとき
中核となる連携の原則
1. 認証とセキュリティ
API キーの管理:
// Store keys in environment variables, never in code
const apiClient = new APIClient({
apiKey: process.env.SERVICE_API_KEY,
baseURL: process.env.SERVICE_BASE_URL
});
OAuth 2.0 フロー:
// Authorization Code Flow
const oauth = new OAuth2Client({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
redirectUri: process.env.REDIRECT_URI,
scopes: ['read:users', 'write:data']
});
// Get authorization URL
const authUrl = oauth.getAuthorizationUrl();
// Exchange code for tokens
const tokens = await oauth.exchangeCode(code);
2. リクエスト/レスポンスの処理
標準化されたリクエスト構造:
async function makeRequest(endpoint, options = {}) {
const defaultHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
'User-Agent': 'MyApp/1.0.0'
};
const response = await fetch(`${baseURL}${endpoint}`, {
...options,
headers: { ...defaultHeaders, ...options.headers }
});
if (!response.ok) {
throw new APIError(response.status, await response.json());
}
return response.json();
}
レスポンスの変換:
class APIClient {
async getUser(userId) {
const raw = await this.request(`/users/${userId}`);
// Transform external API format to internal model
return {
id: raw.user_id,
email: raw.email_address,
name: `${raw.first_name} ${raw.last_name}`,
createdAt: new Date(raw.created_timestamp)
};
}
}
3. エラーハンドリング
構造化されたエラー型:
class APIError extends Error {
constructor(status, body) {
super(`API Error: ${status}`);
this.status = status;
this.body = body;
this.isAPIError = true;
}
isRateLimited() {
return this.status === 429;
}
isUnauthorized() {
return this.status === 401;
}
isServerError() {
return this.status >= 500;
}
}
指数バックオフによるリトライロジック:
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (!error.isAPIError || !error.isServerError()) {
throw error; // Don't retry client errors
}
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await sleep(delay);
}
}
}
4. レート制限
クライアント側のレートリミッター:
class RateLimiter {
constructor(maxRequests, windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = [];
}
async acquire() {
const now = Date.now();
this.requests = this.requests.filter(t => now - t < this.windowMs);
if (this.requests.length >= this.maxRequests) {
const oldestRequest = this.requests[0];
const waitTime = this.windowMs - (now - oldestRequest);
await sleep(waitTime);
return this.acquire();
}
this.requests.push(now);
}
}
const limiter = new RateLimiter(100, 60000); // 100 requests per minute
async function rateLimitedRequest(endpoint, options) {
await limiter.acquire();
return makeRequest(endpoint, options);
}
5. Webhook の処理
Webhook の検証:
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['stripe-signature'];
if (!verifyWebhookSignature(req.body, signature, process.env.STRIPE_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
handleWebhookEvent(event);
res.status(200).send('Received');
});
連携パターン
REST API クライアントパターン
class ServiceAPIClient {
constructor(config) {
this.apiKey = config.apiKey;
this.baseURL = config.baseURL;
this.timeout = config.timeout || 30000;
}
async request(method, endpoint, data = null) {
const options = {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
timeout: this.timeout
};
if (data) {
options.body = JSON.stringify(data);
}
const response = await retryWithBackoff(() =>
fetch(`${this.baseURL}${endpoint}`, options)
);
return response.json();
}
// Resource methods
async getResource(id) {
return this.request('GET', `/resources/${id}`);
}
async createResource(data) {
return this.request('POST', '/resources', data);
}
async updateResource(id, data) {
return this.request('PUT', `/resources/${id}`, data);
}
async deleteResource(id) {
return this.request('DELETE', `/resources/${id}`);
}
}
ページネーションの処理
async function* fetchAllPages(endpoint, pageSize = 100) {
let cursor = null;
do {
const params = new URLSearchParams({
limit: pageSize,
...(cursor && { cursor })
});
const response = await apiClient.request('GET', `${endpoint}?${params}`);
yield response.data;
cursor = response.pagination?.next_cursor;
} while (cursor);
}
// Usage
for await (const page of fetchAllPages('/users')) {
processUsers(page);
}
ベストプラクティス
セキュリティ
- API キーは環境変数またはシークレット管理サービスに保存する
- すべての API 呼び出しで HTTPS を使用する
- Webhook の署名を検証する
- 機密性の高い操作にはリクエスト署名を実装する
- API キーは定期的にローテーションする
信頼性
- 指数バックオフによるリトライロジックを実装する
- レート制限を適切に処理する
- 適切なタイムアウトを設定する
- 障害が発生しているサービスにはサーキットブレーカーを使用する
- デバッグのためにすべての API のやり取りをログに記録する
パフォーマンス
- 適切な場合はレスポンスをキャッシュする
- API がサポートしている場合はリクエストをバッチ化する
- 大きなレスポンスにはストリーミングを使用する
- コネクションプーリングを実装する
- API の利用状況とコストを監視する
モニタリング
- API のレスポンス時間を追跡する
- エラー率の上昇時にアラートを出す
- レート制限の消費量を監視する
- 失敗したリクエストをコンテキスト付きでログに記録する
- 重要な連携にはヘルスチェックを設定する
一般的な連携の例
Stripe による決済処理
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
async function createPaymentIntent(amount, currency = 'usd') {
return await stripe.paymentIntents.create({
amount,
currency,
automatic_payment_methods: { enabled: true }
});
}
SendGrid によるメール送信
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
async function sendEmail(to, subject, html) {
await sgMail.send({
to,
from: process.env.FROM_EMAIL,
subject,
html
});
}
Twilio による SMS
const twilio = require('twilio')(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
async function sendSMS(to, body) {
await twilio.messages.create({
to,
from: process.env.TWILIO_PHONE_NUMBER,
body
});
}
トラブルシューティング
認証の問題
- API キーが正しく設定されているか確認する
- トークンの有効期限を確認する
- OAuth のスコープが適切であることを確認する
- 署名の生成を検証する
レート制限
- クライアント側のレート制限を実装する
- 利用可能な場合はバッチエンドポイントを使用する
- リクエストを時間的に分散させる
- API のプランのアップグレードを検討する
タイムアウトエラー
- 応答の遅いエンドポイントのタイムアウト値を増やす
- リクエストのキャンセル処理を実装する
- 大きなペイロードにはストリーミングを使用する
- ネットワーク接続を確認する
API を連携させる際は、セキュリティ、信頼性、保守性を優先してください。本番環境にデプロイする前に、必ずエラーのシナリオとエッジケースをテストしてください。
コメント
Markdown 対応