mcpField
A
API Integration Specialist

API Integration Specialist

github.com/davila7開発33.0k699 回インストール1 日前に更新
リポジトリ

API Integration Specialist について

アプリケーションやクライアントライブラリに外部 API を統合する開発者向けのガイドです。認証、リクエスト処理、信頼性、セキュリティ、Webhook、トラブルシューティングを扱います。

主な機能

  1. 01API 認証とシークレット管理
  2. 02リクエストとレスポンスの変換
  3. 03構造化エラーとリトライのパターン
  4. 04レート制限とページネーション
  5. 05Webhook 署名の検証

活用シーン

  1. 01サードパーティ API クライアントの構築
  2. 02OAuth または API キー認証の追加
  3. 03レート制限や一時的な障害への対応
  4. 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 を連携させる際は、セキュリティ、信頼性、保守性を優先してください。本番環境にデプロイする前に、必ずエラーのシナリオとエッジケースをテストしてください。

コメント