mcpField
W
workers-runtime-apis

workers-runtime-apis

github.com/secondsky開発24079 回インストール5 週間前に更新
リポジトリ

workers-runtime-apis について

Cloudflare Workers のランタイム API を使う開発者向けのリファレンススキルです。Fetch、Streams、Crypto、Cache、WebSockets、テキストエンコーディングを扱い、利用パターンと一般的なエラーへの対処法を紹介します。

主な機能

  1. 016分野のランタイムAPIを網羅
  2. 02Fetchのタイムアウトと再試行例
  3. 03ストリーム処理の解説
  4. 04暗号化とキャッシュの例
  5. 05一般的なエラーと予防策

活用シーン

  1. 01外部HTTPリクエストのタイムアウト設定
  2. 02大容量ファイルやストリームデータの処理
  3. 03レスポンスのキャッシュ
  4. 04リアルタイムWebSocket機能の構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/secondsky/claude-skills --skill workers-runtime-apis

インストール後、Claude Code で/workers-runtime-apisを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
cache-api.md
crypto-api.md
encoding-api.md
fetch-api.md
streams-api.md
websockets.md
templates/
crypto-operations.ts
fetch-patterns.ts
stream-processing.ts
websocket-handler.ts

詳細

Cloudflare Workers ランタイム API

Workers のランタイム API(Fetch、Streams、Crypto、Cache、WebSockets、テキストエンコーディング)を習得しましょう。

クイックリファレンス

API用途一般的な使用例
FetchHTTP リクエスト外部 API、プロキシ
Streamsデータストリーミング大容量ファイル、リアルタイム処理
Crypto暗号化ハッシュ化、署名、暗号化
Cacheレスポンスのキャッシュパフォーマンスの最適化
WebSocketsリアルタイム接続チャット、ライブ更新
EncodingテキストエンコーディングUTF-8、Base64

クイックスタート:Fetch API

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Basic fetch
    const response = await fetch('https://api.example.com/data');

    // With options
    const postResponse = await fetch('https://api.example.com/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${env.API_KEY}`,
      },
      body: JSON.stringify({ name: 'John' }),
    });

    // Clone for multiple reads
    const clone = response.clone();
    const json = await response.json();
    const text = await clone.text();

    return Response.json(json);
  }
};

重要なルール

  1. 外部リクエストには必ずタイムアウトを設定する - Workers の制限時間は 30 秒ですが、外部 API は応答しなくなる可能性があります
  2. 本文を読み取る前にレスポンスを複製する - 本文は一度しか読み取れません
  3. 大きなペイロードにはストリーミングを使用する - レスポンス全体をメモリにバッファリングしないでください
  4. 外部 API のレスポンスをキャッシュする - レイテンシと API コストを削減できます
  5. Crypto 操作は try/catch で処理する - 入力が無効な場合、エラーがスローされます
  6. コスト削減には WebSocket の休止機能を使う - 休止機能を備えた Durable Objects を使用します

防止できる主なエラー 10 件

エラー症状防止方法
本文はすでに読み取り済みTypeError: Body has already been consumed読み取る前にレスポンスを複製する
Fetch のタイムアウトリクエストが停止し、Worker がタイムアウトするAbortController とタイムアウトを使用する
無効な JSONSyntaxError: Unexpected tokenパースする前に content-type を確認する
ストリームがロックされているTypeError: ReadableStream is lockedストリームを複数回読み取らない
Crypto キーエラーDOMException: Invalid keyDataキーの形式とアルゴリズムを検証する
キャッシュミスレスポンスではなく undefined を返す返す前にキャッシュを確認する
WebSocket の切断接続が予期せず切断されるclose イベントを処理し、再接続を実装する
エンコーディングエラーTypeError: Invalid code pointTextEncoder/TextDecoder を正しく使用する
CORS によるブロックブラウザーがレスポンスを拒否する適切な CORS ヘッダーを追加する
リクエストサイズ413 Request Entity Too Large大きなアップロードをストリーミングする

Fetch API のパターン

タイムアウトあり
async function fetchWithTimeout(url: string, timeout: number = 5000): Promise<Response> {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, { signal: controller.signal });
    return response;
  } finally {
    clearTimeout(timeoutId);
  }
}
リトライあり
async function fetchWithRetry(
  url: string,
  options: RequestInit = {},
  retries: number = 3
): Promise<Response> {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) return response;

      // Retry on 5xx errors
      if (response.status >= 500 && i < retries - 1) {
        await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
        continue;
      }

      return response;
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
  throw new Error('Max retries exceeded');
}

Streams API

Transform Stream
function createUppercaseStream(): TransformStream<string, string> {
  return new TransformStream({
    transform(chunk, controller) {
      controller.enqueue(chunk.toUpperCase());
    }
  });
}

// Usage
const response = await fetch('https://example.com/text');
const transformed = response.body!
  .pipeThrough(new TextDecoderStream())
  .pipeThrough(createUppercaseStream())
  .pipeThrough(new TextEncoderStream());

return new Response(transformed);
大きなレスポンスのストリーミング
async function streamLargeFile(url: string): Promise<Response> {
  const response = await fetch(url);

  // Stream directly without buffering
  return new Response(response.body, {
    headers: {
      'Content-Type': response.headers.get('Content-Type') || 'application/octet-stream',
    },
  });
}

Crypto API

ハッシュ化
async function sha256(data: string): Promise<string> {
  const encoder = new TextEncoder();
  const dataBuffer = encoder.encode(data);
  const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
HMAC 署名
async function signHMAC(key: string, data: string): Promise<string> {
  const encoder = new TextEncoder();
  const keyData = encoder.encode(key);
  const dataBuffer = encoder.encode(data);

  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    keyData,
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );

  const signature = await crypto.subtle.sign('HMAC', cryptoKey, dataBuffer);
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
}

Cache API

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const cache = caches.default;
    const cacheKey = new Request(request.url, { method: 'GET' });

    // Check cache
    let response = await cache.match(cacheKey);
    if (response) {
      return response;
    }

    // Fetch and cache
    response = await fetch(request);
    response = new Response(response.body, response);
    response.headers.set('Cache-Control', 'public, max-age=3600');

    // Store in cache (don't await)
    ctx.waitUntil(cache.put(cacheKey, response.clone()));

    return response;
  }
};

WebSockets(Durable Objects)

// Durable Object with WebSocket hibernation
export class WebSocketRoom {
  state: DurableObjectState;

  constructor(state: DurableObjectState) {
    this.state = state;
  }

  async fetch(request: Request): Promise<Response> {
    const upgradeHeader = request.headers.get('Upgrade');
    if (upgradeHeader !== 'websocket') {
      return new Response('Expected websocket', { status: 426 });
    }

    const pair = new WebSocketPair();
    const [client, server] = Object.values(pair);

    // Accept with hibernation
    this.state.acceptWebSocket(server);

    return new Response(null, { status: 101, webSocket: client });
  }

  async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer) {
    // Handle incoming message
    const data = typeof message === 'string' ? message : new TextDecoder().decode(message);

    // Broadcast to all connected clients
    for (const client of this.state.getWebSockets()) {
      client.send(data);
    }
  }

  async webSocketClose(ws: WebSocket, code: number, reason: string) {
    ws.close(code, reason);
  }
}

リファレンスを読み込むタイミング

タスクに応じて、特定のリファレンスを読み込みます。

  • HTTP リクエストを送信する場合 → タイムアウト、リトライ、プロキシのパターンについては references/fetch-api.md を読み込みます
  • 大きなデータを処理する場合 → TransformStream、チャンク分割については references/streams-api.md を読み込みます
  • 暗号化/署名を行う場合 → AES、RSA、JWT の検証については references/crypto-api.md を読み込みます
  • レスポンスをキャッシュする場合 → Cache API のパターン、TTL 戦略については references/cache-api.md を読み込みます
  • リアルタイム機能を実装する場合 → WebSocket のパターン、Durable Objects については references/websockets.md を読み込みます
  • テキストをエンコードする場合 → TextEncoder、Base64、Unicode については references/encoding-api.md を読み込みます

テンプレート

テンプレート用途使用する場面
templates/fetch-patterns.tsHTTP リクエストユーティリティAPI クライアントの構築
templates/stream-processing.tsストリームの変換大きなファイルの処理
templates/crypto-operations.tsCrypto ユーティリティ署名、ハッシュ化、暗号化
templates/websocket-handler.tsWebSocket DOリアルタイムアプリケーション

リソース

コメント