extension-http-outcalls について
バックエンドカナisterから外部 API を呼び出す Caffeine AI 向けのスキルです。プロバイダー側の応答制限と、curl およびコンプライアンスチェックによる検証を重視します。
主な機能
- 01複数の HTTP メソッドに対応
- 02サーバー側での応答範囲制限
- 03応答サイズと件数の上限
- 04Motoko 外部呼び出しモジュール
- 05curl とコンプライアンス検査の手順
活用シーン
- 01ユーザー指定の識別子で単一エンティティを検索
- 02ユーザーがページごとに閲覧する一覧を取得
- 03デプロイ前に外部 API 呼び出しを検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ caffeinelabs/ skills --skill extension-http-outcallsインストール後、Claude Code で/extension-http-outcallsを入力して読み込まれたか確認します。
詳細
HTTP Outcalls
Caffeine AI 向けの HTTP outcalls 拡張機能です。
概要
このスキルでは、GET、HEAD、POST、PUT、DELETE、PATCH を含む、バックエンド canister からの HTTP リクエストの要件を説明します。外部 API やサービスと連携する場合は、必ず使用してください。
重要な要件
次のルールに従ってください。
- プロバイダー側で強制される上限付き API リクエストを必ず使用してください。 リクエストでは、機能に適した識別子、ページネーション、時間範囲、地理的範囲、結果件数、またはその他のサーバー側の上限によって、レスポンスを制限する必要があります。 各レスポンスは最大 10_000 件かつ最大 1 MB に制限し、必要に応じてページネーションしてください。
- 機能に合った上限を必ず選択してください。 5 種類の上限は相互に置き換えられません。ユーザーが指定する値(便名、注文 ID、ティッカー、郵便番号など)で 1 つのエンティティを検索する機能では、識別子による上限のみが正しい選択です。コレクションをページネーションしてそのエンティティを探すのはアンチパターンであり、代替手段ではありません。各ページがどれほど小さくても、処理量はコレクション全体に応じて増えるためです。ページネーションは、ユーザーが意図的にページをめくるリストに使用するものであり、検索には使用しません。
- すべての上限を実際の Motoko http リクエストに必ず設定してください。 ローカルテストでのみ使用される上限では、canister を保護できません。
- 上限のないコレクションを取得して、canister 内でフィルタリングすることは絶対にしないでください。 想定レスポンスサイズ、通常のトラフィック、現在のデータセットが小さいことは、上限にはなりません。
- プロバイダーがレスポンスの上限を強制できず、必要なデータを提供できない場合は、その API を拒否するか、機能の範囲を狭めてください。 安全でないとわかっているフォールバックを実装してはいけません。
- curl の実装に対してローカルでテストしてください。 1:1 の curl 呼び出しが成功し、アプリが使用するすべてのフィールドを返すことを確認してください。Motoko コードを変更した場合は、ローカルの curl テストをやり直してください。
check_canister_api_complianceで上限を確認してください。 このツールはエンドポイントを調査してレスポンスがこれらの制限内か測定し、デプロイゲートの背後で実行されるため、拒否されたエンドポイントはリリースできません。
上記の 1 MB と 10_000 件という制限は、このモジュール独自の上限です。
defaultMaxResponseBytes は 1 MB であり、check_canister_api_compliance は
この 2 つの数値に対して正確に測定します。ただし、これらの上限に達する前に拒否します。URL にサーバー側の上限が含まれていない場合、調査したレスポンスがバイト数の上限の 4 分の 1 を超えるか、1_000 件を超えた時点でブロックします。この範囲は危険です。単発の curl は通っても、その後データが増え、canister がペイロードの解析中にメッセージごとの命令数上限を超えるおそれがあるためです。より厳しい上限を前提に設計してください。リクエストにはサーバー側の上限を設定してください。
誤った上限の選択
便の検索では便名を受け取り、1 機の航空機を返す必要があります。https://opensky-network.org/api/states/all(世界中で飛行中のすべての航空機、およそ 10-13k 行)を取得し、解析した結果を Motoko で走査して 1 つのコールサインを探すのは誤りです。canister は単一の検索に答えるために、世界中のすべてのレコードをダウンロードして解析することになり、メッセージは拒否されます。
IC0522: Canister exceeded the limit of 40000000000 instructions for single message execution。コード自体に問題があるようには見えません。URL は有効で、パース処理はコンパイルでき、単発の curl は 200 を返します。
これはバイト数の上限ではなく、命令数の上限です。ページサイズを小さくしても解決しません。1 行を見つけるために、canister は依然としてコレクション全体を走査する必要があります。
プロバイダーはすでに適切な上限を提供しています。同じエンドポイントの ?icao24=<hex> は識別子による上限で、数 KB のレスポンスから 1 機の航空機、つまり 1 レコードだけを解析できます。
逆方向、つまり外部クライアントが HTTPS 経由で canister に接続する場合(webhook、curl、ボットのコールバック)は、extension-http-endpoints を使用してください。
バックエンド
バックエンドで実行する必要がある HTTP アウトコールについて:
既存のモジュール mo:caffeineai-http-outcalls/outcall.mo は、IC がサポートするすべての HTTP メソッドに対応する汎用の上限付きリクエスト関数と、後方互換性のある GET および POST ヘルパーを提供します。
module {
public type TransformationInput = {
context : Blob;
response : IC.HttpRequestResult;
};
public type TransformationOutput = IC.HttpRequestResult;
public type Transform = query TransformationInput -> async TransformationOutput;
public type Header = {
name: Text;
value: Text;
};
public type Method = {
#get;
#head;
#post;
#put;
#delete;
#patch;
};
public type Request = {
url : Text;
method : Method;
headers : [Header];
body : ?Blob;
maxResponseBytes : Nat64;
transform : Transform;
};
public type Response = IC.HttpRequestResult;
public let defaultMaxResponseBytes : Nat64;
// Helper function for the transform callback used by the IC on HTTP outcalls.
public func transform(input : TransformationInput) : TransformationOutput;
// Generic bounded request supporting GET, HEAD, POST, PUT, DELETE, and PATCH.
public func httpRequest(request : Request) : async Response;
// HTTP GET request with a transform callback function.
public func httpGetRequest(url : Text, extraHeaders: [Header], transform : Transform) : async Text;
// HTTP POST request, specifying a transform callback.
public func httpPostRequest(url : Text, extraHeaders: [Header], body : Text, transform : Transform) : async Text;
};
ステータス、ヘッダー、カスタムのレスポンス上限、または GET と POST 以外のメソッドが必要な場合は、httpRequest を使用してください。maxResponseBytes で上限をより低く設定できます。モジュールはすべてのリクエストを defaultMaxResponseBytes(1 MB)に制限します。モジュールはすべての HTTP アウトコールを is_replicated = ?false で実行するため、呼び出し側がレプリケート実行を有効にすることはできません。シンプルな GET には、後方互換性のあるヘルパーが最短の方法です。
import Text "mo:core/Text";
import OutCall "mo:caffeineai-http-outcalls/outcall";
actor {
public query func transform(input : OutCall.TransformationInput) : async OutCall.TransformationOutput {
OutCall.transform(input);
};
func setItemActive() : async OutCall.Response {
await OutCall.httpRequest({
url = "https://api.example.com/items/123";
method = #patch;
headers = [{ name = "Content-Type"; value = "application/json" }];
body = ?("{\"active\":true}".encodeUtf8());
maxResponseBytes = 100_000;
transform;
});
};
func makeGetOutcall(url : Text) : async Text {
await OutCall.httpGetRequest(url, [], transform);
};
};
httpPostRequest を使った POST も同様です。
外部 API リクエストをすべて検証する
HTTP アウトコールを完了と見なす前に、同等のリクエストを curl でローカルに実行してください。記憶している API ドキュメントや、Motoko コードがコンパイルできることだけに頼ってはいけません。以下のチェックはすべて必須です。いずれかのチェックに失敗した場合、HTTP アウトコールは未完了であり、デプロイに進んではいけません。
- Motoko で実装したものと完全に同じリクエストを必ずテストしてください: 同じ HTTP メソッド、API バージョン、エンドポイントパス、クエリパラメーター、ヘッダー、本文を使用します。関連するエンドポイントをテストしたり、実装で使用していないパラメーターを追加したりしても、有効な検証にはなりません。
- 代表的なユーザー入力を1つ選び、API リクエストに変換されるまでのすべての処理をエンドツーエンドでたどり、その結果として得られるリクエストを必ずテストしてください。 たとえば、ユーザーがある識別子を入力し、プロバイダーが別の形式の識別子を要求する場合、その変換をエンドツーエンドで検証します。プロバイダーのベースエンドポイントや一覧取得エンドポイントだけを呼び出しても不十分です。
- 消費するレスポンスの契約を必ず検証してください。
curl --fail-with-body --silent --show-errorを使ってリクエストを実行します。成功ステータスに加えて、アプリが使用するすべてのレスポンスフィールドとその型を検証してください。単に有効な JSON が返るだけでは不十分です。 - 実装で使う正確な URL とメソッドに対して、必ず
check_canister_api_complianceを実行してください。 このチェックは、レスポンスがアウトコールのバイト数上限とエントリー数上限に収まるかを測定し、その URL がサーバー側で、機械的に、かつデプロイゲートを通じて制限されているかを報告します。これにより、許可済みのホストではないホストへのアウトコールがデプロイされることを防ぎます。エンドポイントが拒否された場合は、互換性のある公開 API を選ぶか、機能を正直に縮小してください。取得件数に上限のないリクエストを実装して、カナスター内で絞り込んではいけません。
レスポンスの上限を確認するのはこのチェックの役割であり、curl の役割ではありません。上記のチェックが代わりにできないのは、エンドポイントを調べるものであってアプリを調べるものではないためです。そのため、アプリがどのレスポンスフィールドを読み取るのか、またユーザーが URL を生成するために何を入力したのかは把握できません。
リクエストに失敗した場合や上記のチェックが1つでも満たされない場合は、ステータスとレスポンス本文を調べてください。ウェブ検索を使って、プロバイダーの最新の公式 API ドキュメントとリリースノートまたは移行ノートを確認してください。現在の API バージョン、エンドポイント、パラメーター名と形式、必須ヘッダー、リクエスト本文を確認してください。失敗を推測で切り抜けてはいけません。動作する REST リクエストに合わせて Motoko リクエストを修正し、curl を再実行してください。すべてのチェックに合格するまで繰り返した後、バックエンドのチェックを再実行してください。必須のチェックが欠けている、または失敗している間は、完了を報告してはいけません。
よくある失敗の手掛かり:400 はパラメーターまたは本文の形式が無効であることを示します。404/410 は古いエンドポイントまたは API バージョンを示すことがよくあります。405 はメソッドが誤っていることを示し、415 はコンテンツタイプが誤っていることを示します。429 と 5xx の応答は、現在の公式ドキュメントに照らしてリクエストが正しいことを確認してから、クォータまたはプロバイダーの可用性に関する問題として扱ってください。