building-nango-functions-locally について
チェックアウト済みのNangoプロジェクトでアクションと同期処理を構築するスキルです。同期処理ではプロバイダーに応じたチェックポイントと削除戦略を求め、プロジェクトのローカル検証・テスト・デプロイ手順を使います。
主な機能
- 01createAction()によるアクション構築
- 02createSync()による同期処理の構築
- 03チェックポイントと削除処理の計画
- 04プロバイダー入力とスキーマの検証
- 05ローカルのコンパイル・ドライラン・テスト・デプロイ
活用シーン
- 01ユーザー起動型のプロバイダーAPIアクション実装
- 02定期実行またはWebhook駆動のデータ同期構築
- 03チェックポイントを使ったページング同期の再開
- 04Nango関数のローカル検証とテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nangohq/ skills --skill building-nango-functions-locallyインストール後、Claude Code で/building-nango-functions-locallyを入力して読み込まれたか確認します。
同梱ファイルreferences/actions.mdreferences/syncs.md
詳細
Nango 関数をローカルで構築する
チェックアウト済みの Nango プロジェクトで、ローカル CLI による検証・テストのワークフローを使って、デプロイ可能な Nango のアクションと同期を構築します。
実装範囲
- Nango 関数の実装を構築または変更する
- Nango で
createAction()を使ってアクションを構築する - Nango で
createSync()を使って同期を構築する - コンパイル、dryrun、テスト、デプロイの手順には、アクティブなワークフロースキルを使用する
同期戦略の確認(コードを書く前に必須)
同期の場合は、コードを書く前に references/syncs.md を読み、まず次のいずれかの方法を明示してください。
- チェックポイント方式:
- 変更元(
updated_at、modified_since、変更レコード用エンドポイント、カーソル、ページトークン、オフセット/ページ、since_id、または webhook) - チェックポイントスキーマ
- チェックポイントによってプロバイダーへのリクエストまたは再開状態がどう変わるか
- リクエストが引き続きデータセット全体を走査するのか、変更された行のみを返すのか
- 削除戦略
- 変更元(
- フルリフレッシュが必要な理由:
- ドキュメントまたはサンプルペイロードに記載された、プロバイダー側の具体的な制限
- その制限によりチェックポイントを利用できない理由
無効な同期実装:
- 単純だからという理由でフルリフレッシュを行う
getCheckpoint()を使わずにsaveCheckpoint()を呼び出す- チェックポイントを読み取る、または保存するものの、リクエストパラメーターやページネーション状態に反映しない
- 新しい同期で
syncType: 'incremental'またはnango.lastSyncDateを使う checkpointスキーマがないフルリフレッシュ、または各ページの後にチェックポイントが保存されないフルリフレッシュ — 実行時間の上限を超えると、実行は毎回 1 ページ目から再開されますsaveCheckpoint()の呼び出しを、次のページが残っている場合に限定する(例:if (nextCursor) { await nango.saveCheckpoint(...) })。最後のページを含む、成功したすべてのページでsaveCheckpoint()を呼び出す必要があります。そうしないと、1 ページだけの同期でチェックポイント行がないままclearCheckpoint()に到達し、checkpoint_conflictエラーが発生します。clearCheckpoint()より前にtrackDeletesEnd()を呼び出す、または先にclearCheckpoint()を呼び出さずにtrackDeletesEnd()を呼び出す- 変更分のみを取得するチェックポイント(
modified_after、updated_after、変更レコード用エンドポイント)とともにtrackDeletesStart()/trackDeletesEnd()を使う。これらのリクエストでは変更のない行が除外されるため、trackDeletesEnd()によって誤って削除されます。 - 削除レコードのイベントを明示的に処理する増分同期で
trackDeletesStart()/trackDeletesEnd()を使う
方法を選択する
アクション:
createAction()で構築する、ユーザーが実行する単発のリクエスト- コードを書く前に
references/actions.mdを読む
同期:
createSync()で構築する、スケジュール実行または webhook 駆動のキャッシュ更新- 先に同期戦略の確認を完了する
- コードを書く前に
references/syncs.mdを読む
必須入力(不足している場合はユーザーに確認)
常に必要:
- Integration ID(プロバイダー名)
- スクリプト/関数名(kebab-case)
- API リファレンス URL またはサンプルレスポンス
- アクティブなワークフローで関数を検証または dryrun する場合は、Connection ID
アクション固有:
- ユースケースの概要
- 入力パラメーター
- 出力フィールド
- 必要な場合は Metadata JSON
- アクティブなワークフローでアクションを検証または dryrun する場合は、テスト入力 JSON(入力不要のアクションには
{}を使用)
同期固有:
- モデル名(単数形、PascalCase)
- 実行頻度(1 時間ごと、5 分ごとなど)
- チェックポイントスキーマ(タイムスタンプ、カーソル、ページトークン、オフセット/ページ、
since_id、または複合型) - チェックポイントによってプロバイダーへのリクエストまたは再開状態がどう変わるか
- 削除戦略(削除レコード用エンドポイント/webhook、またはフルリフレッシュが必要な理由)
- フルリフレッシュを提案する場合は、チェックポイントの利用を妨げる、ドキュメント/サンプルレスポンスに記載されたプロバイダー側の具体的な制限
- 必要な場合は Metadata JSON(team_id、workspace_id)
外部の必須情報が不足している場合は、リポジトリとプロバイダーのドキュメントを確認したうえで、要点を絞って質問してください。同期では、プロバイダーが対応している場合、チェックポイントと削除戦略を選んでください。有効なチェックポイント戦略が見つからない場合は、フルリフレッシュを実装する前に、その理由を具体的に説明してください。
必ず守るルール
共有プラットフォームの制約
- Nango 関数では
createAction()/createSync()を使用します。 - 任意のパッケージは追加できません。選択したワークフローでサポートされている場合に限り相対インポートを使用してください。組み込みで使用できるものには
zod、crypto/node:crypto、url/node:urlがあります。 - 関数コードの外で接続の検索、認証情報の取得、プロキシ呼び出しを行う場合は、Nango HTTP API を使用してください。CLI のトークンや接続に関するコマンドを作り出さないでください。
- 各プロバイダー呼び出しの上に、API ドキュメントへのリンクコメントを追加してください。
- アクションの出力は 2MB を超えられません。
- ファイルのアップロードとダウンロードはアクションとして実装できません(サンドボックス化されたランタイムでは
fsとaxiosが使えず、出力上限は 2 MB です)。代わりに{integration}/proxy/内で@nangohq/nodeを使用したプロキシスクリプトを使ってください。詳しくはreferences/actions.mdを参照してください。 - HTTP の再試行回数のデフォルトは
0です。retriesは意図的に設定してください。通常の上限は3としてください。同期処理でのプロバイダー呼び出しでは、安全かつ必要であることがドキュメントで証明されない限り、3を超える値は実質的に禁止です。API が冪等性をサポートしていない場合、冪等でない書き込み処理では再試行を避けてください。 - 非推奨の関数定義ルーティングフィールドは設定しないでください。アクションの
endpointと同期のendpointsが該当します。SDK/API からアクション名でアクションを実行し、レコード API から同期レコードを取得してください。
同期のルール
- 同期レコードには安定した文字列の
idが必要です。 - 新しい同期では
checkpointスキーマを定義し、最初にnango.getCheckpoint()を呼び出し、各ページまたはバッチの処理後にnango.saveCheckpoint()を呼び出してください。 - チェックポイントが有効なのは、リクエストまたは再開状態(
since、updated_after、cursor、page_token、offset、page、since_idなど)に反映される場合に限られます。チェックポイントを保存しても使用しない場合は、増分同期ではありません。 - 新しい同期では
syncType: 'incremental'やnango.lastSyncDateを使用しないでください。 - デフォルトでは
nango.paginate(...)+nango.batchSave(...)を使用してください。cursor、link、offsetによるページネーションが使える場合は、while (true)による手動ループを避けてください。 - プロバイダーから削除、削除済みを示すレコード、または削除ウェブフックが返される場合は、
batchDelete()を優先してください。 - プロバイダーから変更、削除、再開状態を取得できない場合、またはデータセットがごく小さい場合に限り、フルリフレッシュを使用してください。
- フルリフレッシュを行う場合は、プロバイダーの制約を示すドキュメントまたはペイロード内の該当箇所を正確に引用してください。「その方が簡単だから」では不十分です。
- フルリフレッシュの同期でも、増分同期と同様に、ページネーションの進捗を保持するための
checkpointスキーマ(ページ、カーソル、オフセット)を設定する必要があります。Nango の同期は実行時間に制限のある実行ウィンドウ内で動作します。チェックポイントのないフルリフレッシュは、ウィンドウを超えるたびに毎回 1 ページ目から再開されます。同じ序盤のページを再取得してコンピューティングリソースを浪費し、残りのページに到達できません。 deleteRecordsFromPreviousExecutions()は非推奨です。フルリフレッシュでは、実行のたびにtrackDeletesStart()を呼び出してください(安全で冪等です。すでに開始済みのウィンドウの開始位置は上書きされません)。その後、各ページの後にsaveCheckpoint()を呼び出し、最後のページの後にclearCheckpoint()を呼び出してから、trackDeletesEnd()を呼び出してください。- フルリフレッシュでは、最後のページを含む成功したすべてのページの後に
saveCheckpoint()を呼び出してから、clearCheckpoint()を呼び出してください。「残りのページがある」という条件で保存を制御してはいけません。個別の実行経路でチェックポイントがまったく作成されない場合(たとえば、処理対象のページがない場合)は、その経路でclearCheckpoint()を呼び出さないでください。実行時にcheckpoint_conflictが発生します。この例外を、最終ページの保存の代わりにしてはいけません。 trackDeletesStart()/trackDeletesEnd()と、変更分のみを対象とするチェックポイント(modified_after、updated_after、変更されたレコードを返すエンドポイントなど)を組み合わせてはいけません。変更のない行が対象から漏れるため、trackDeletesEnd()によってそれらの行が削除されます。- チェックポイントを使うフルリフレッシュも、フルリフレッシュであることに変わりはありません。チェックポイントを完了してクリアする実行でのみ
trackDeletesEnd()を呼び出してください。 - 同期にメタデータ(例:
team_id、workspace_id、guild_id)が必要な場合は、autoStart: falseを設定してください。呼び出し側がメタデータを設定するまで同期は実行できないため、自動的に開始すると失敗します。
規約
- フィールドの大文字・小文字は外部 API に合わせてください。パススルーフィールドはプロバイダーの表記を維持し、パススルー以外のフィールドは、その API で多数を占める表記を使用してください。
- 明示的なフィールド名を優先してください。
- ID、タイムスタンプ、列挙型、URL の例を
.describe()に追加してください。 anyは避け、インラインのマッピング型を使用してください。- リストアクションでは、
cursorと、その API で多数を占める表記(next_cursor、nextCursorなど)の次のカーソル用フィールドを公開してください。 - カスタム検証またはログ記録が必要な場合に限り、
nango.zodValidateInput()を使用してください。それ以外の場合は、スキーマと選択した検証ワークフローを利用してください。
スキーマのセマンティクス
- 必須でない入力は、デフォルトで
.optional()にしてください。 nullに意味がある場合(通常は更新時のクリア)に限り、.nullable()を使用してください。呼び出し元がフィールドを省略する場合もあるなら、.optional()も追加してください。- プロバイダーの生スキーマはプロバイダーに合わせてください。省略されたフィールドには
.optional()、明示的なnullには.nullable()を使用し、プロバイダーが実際に両方を使う場合に限り.nullish()を使用してください。 - 最終的なアクション出力と正規化された同期モデルでは、
.optional()を優先してください。また、nullに意味がある場合を除き、上流からのnullは省略に正規化してください。 - 生成スキーマでは、必須でない入力と正規化された出力にデフォルトで
.optional()を使用してください。上流の契約上の根拠がある場合に限り、型の範囲を広げてください。 z.union([z.null(), T])やz.union([T, z.null()])よりも.nullable()を優先してください。- 出力スキーマで許可されている場合に限り、
nullを返してください。 z.object()はデフォルトで不明なキーを除去します。プロバイダーの値をそのまま通す場合は、最小限の絞り込みとともにz.object({}).passthrough()、z.record(z.unknown())、またはz.unknown()を使用してください。
フィールド名と大文字・小文字の規則
- API で多数を占める表記を使い、明示的な接尾辞を使用してください。ID(
user_id、userId)、名前(channel_name、channelName)、メールアドレス(user_email、userEmail)、URL(callback_url、callbackUrl)、タイムスタンプ(created_at、createdAt)。
マッピング例(API が異なるパラメーター名を想定している場合):
const InputSchema = z.object({
userId: z.string()
});
const config: ProxyConfiguration = {
endpoint: 'users.info',
params: {
user: input.userId
},
retries: 3
};
API が snake_case の場合は、代わりに user_id を使用してください。目的は API との一貫性です。
参考資料
- アクションのパターン、CRUD の例、メタデータの使用方法、ActionError の例:
references/actions.md - 同期のパターン、具体的なチェックポイントの例、削除戦略、フルリフレッシュへのフォールバック:
references/syncs.md
便利な Nango ドキュメント(クイックリンク)
- Functions ランタイム SDK リファレンス:https://nango.dev/docs/reference/functions
- アクションの実装:https://nango.dev/docs/implementation-guides/use-cases/actions/implement-an-action
- 同期の実装:https://nango.dev/docs/implementation-guides/use-cases/syncs/implement-a-sync
- チェックポイント:https://nango.dev/docs/implementation-guides/use-cases/syncs/checkpoints
- 削除の検出(フルと増分):https://nango.dev/docs/implementation-guides/use-cases/syncs/deletion-detection
- インテグレーションのテスト(dryrun、
--save、Vitest):https://nango.dev/docs/implementation-guides/platform/functions/testing - Nango HTTP API リファレンス:https://nango.dev/docs/reference/api
API ドキュメントが表示されない場合
ウェブから取得したドキュメントが不完全な場合(JavaScript でレンダリングされている場合):
- ユーザーにサンプルレスポンスを依頼してください
- ワークスペースに既存の Nango アクションまたは同期がある場合は、パターンとして利用してください
- 成功するまで、スキル固有の検証または dryrun のワークフローを使用してください
ワークフロー(必須)
- アクションか同期かを判断します。
- 該当するリファレンスファイル(
references/actions.mdまたはreferences/syncs.md)を読みます。 - 同期の場合は、プロバイダーのドキュメントまたはペイロードを調べてチェックポイントと削除を確認し、エンドポイントが全データを返すのか、変更された行を返すのかを判断して、Sync Strategy Gate を完了します。
- 必要な入力と外部の値を集めます。接続の検索、認証情報、または検出には、Nango HTTP API を使用します。
- これが Zero YAML の TypeScript プロジェクト(
no nango.yaml)であること、および Nango のルート(.nango/が存在する)にいることを確認します。 {integrationId}/actions/または{integrationId}/syncs/の関数を作成または更新し、共通のスキーマと大文字小文字の規則を適用してから、index.tsに登録します。nango dryrun ... --validate -e dev --no-interactive --auto-confirmで検証します。- 検証に合格できない場合は停止し、不足している外部状態または入力を報告します。
- 検証に合格したら、
nango dryrun ... --save、次にnango generate:tests、その後npm testを実行します。 - 要求された場合に限り、
nango deploy devでデプロイします。
前提条件(コードを書く前に実施)
TypeScript プロジェクトであることを確認(nango.yaml なし)
このスキルは、createAction() / createSync() を使用する TypeScript プロジェクトのみをサポートします。
ls nango.yaml 2>/dev/null && echo "YAML PROJECT DETECTED" || echo "OK - No nango.yaml"
YAML PROJECT DETECTED と表示された場合:
- 直ちに停止します。
- まず TypeScript 形式にアップグレードするようユーザーに伝えます。
- YAML と TypeScript を混在させないでください。
リファレンス:https://nango.dev/docs/implementation-guides/platform/migrations/migrate-to-zero-yaml
Nango プロジェクトのルートを確認
Nango のルートを確認するまで、ファイルを作成しないでください。
ls -la .nango/ 2>/dev/null && pwd && echo "IN NANGO PROJECT ROOT" || echo "NOT in Nango root"
NOT in Nango root と表示された場合:
.nango/があるディレクトリにcdします。- 確認を再実行します。
- 回避策として絶対パスを使用しないでください。
すべてのファイルパスは Nango のルートからの相対パスでなければなりません。すでに Nango のルートにいる状態で余分なプレフィックスを付けてファイルを作成すると、ビルドが失敗する入れ子のディレクトリが作られます。
プロジェクト構成と命名規則
./
|-- .nango/
|-- index.ts
|-- hubspot/
| |-- actions/
| | `-- create-contact.ts
| `-- syncs/
| `-- fetch-contacts.ts
`-- slack/
`-- actions/
`-- post-message.ts
- プロバイダーのディレクトリ:小文字(
hubspot、slack) - アクションファイル:ケバブケース(
create-contact.ts) - 同期ファイル:ケバブケース(多くのチームでは
fetch-プレフィックスを使いますが、任意です) - 1 ファイルにつき 1 関数
- すべてのアクションと同期を
index.tsにインポートする必要があります
index.ts にスクリプトを登録(必須)
副作用インポートのみを使用します。.js 拡張子を含めてください。
// index.ts
import './github/actions/get-top-contributor.js';
import './github/syncs/fetch-issues.js';
登録が誤っている場合の症状:ファイルはコンパイルされますが、No entry points found in index.ts... と表示されるか、関数が表示されません。
ドライラン、モック、テスト(必須)
必須の手順:
nango dryrun ... --validate -e dev --no-interactive --auto-confirmを合格するまで実行します。- アクション:必ず
--input '{...}'を渡します(入力不要のアクションには--input '{}'を使用します)。 - 同期:再開された実行をシミュレートする必要がある場合は、
--checkpoint '{...}'を使用します。 - 検証に合格できない場合は停止し、必要な外部状態または不足している入力を明記します。
- 検証に合格したら、
nango dryrun ... --save -e dev --no-interactive --auto-confirmを実行して<script-name>.test.jsonを生成します。 nango generate:testsを実行し、その後npm testを実行します。
例:
# Validate an action
nango dryrun <action-name> <connection-id> --validate -e dev --no-interactive --auto-confirm --input '{"key":"value"}'
# Validate a no-input action
nango dryrun <action-name> <connection-id> --validate -e dev --no-interactive --auto-confirm --input '{}'
# Validate a sync
nango dryrun <sync-name> <connection-id> --validate -e dev --no-interactive --auto-confirm
# Validate a resumed sync with a checkpoint
nango dryrun <sync-name> <connection-id> --validate -e dev --no-interactive --auto-confirm --checkpoint '{"updated_after":"2024-01-15T00:00:00Z"}'
# Record action mocks after validation passes
nango dryrun <action-name> <connection-id> --save -e dev --no-interactive --auto-confirm --input '{"key":"value"}'
# Record sync mocks after validation passes
nango dryrun <sync-name> <connection-id> --save -e dev --no-interactive --auto-confirm
# Stub metadata when needed
nango dryrun <script-name> <connection-id> --validate -e dev --no-interactive --auto-confirm --metadata '{"team_id":"123"}'
厳守事項:
<script-name>.test.jsonは生成された出力として扱います。作成、編集、名前変更、移動はしないでください。- モックが誤っている、または古くなっている場合は、コードを修正して
--saveで再記録します。 - 404、401、429、またはタイムアウトのケースで、
*.test.jsonにエラーペイロードをハードコードしないでください。vi.spyOn(...)を使った Vitest テストを使用します。 - 接続 ID は 2 番目の位置引数です。
--connection-idは使用しないでください。 - 複数のインテグレーションでスクリプト名が重複する場合は、
--integration-id <integration-id>を使用します。 - 新しい増分同期では
--checkpointを優先します。--lastSyncDateは旧式のパターンです。 nangoがPATHにない場合は、npx nango ...を使用します。- CLI のアップグレードプロンプトが自動化を妨げる場合があります。必要に応じて
NANGO_CLI_UPGRADE_MODE=ignoreを設定します。
リファレンス:https://nango.dev/docs/implementation-guides/platform/functions/testing
デプロイ(任意)
Nango アカウント内の環境に関数をデプロイします。
nango deploy dev
# Deploy only one function
nango deploy --action <action-name> dev
nango deploy --sync <sync-name> dev
リファレンス:https://nango.dev/docs/implementation-guides/use-cases/actions/implement-an-action
最終チェックリスト
アクション:
- Nango のルートを確認済み
- アクションのパターンには
references/actions.mdを使用済み - スキーマと型が明確であり、値が欠落している場合のルールがプロバイダーと正規化済みのコントラクトに合致している
- 必要な場合は
createAction()に入力、出力、スコープが含まれており、非推奨のendpointは省略されている - フィールドでは、ケーシングをそのまま維持するか、API の過半数を占めるケーシングを使用している
- プロバイダー呼び出しに API ドキュメントへのリンクコメントと、意図的なリトライが含まれている
- 想定される失敗には
nango.ActionErrorを使用している -
index.tsに登録済み -
--validate -e dev --no-interactive --auto-confirm --input '{...}'でドライランが成功する -
--validateの実行後、nango dryrun ... --saveにより<action-name>.test.jsonが生成された -
nango generate:testsを実行済みで、npm testが合格する
同期:
- Nango のルートを確認済み
- 同期のパターンには
references/syncs.mdを使用済み - モデルマップが定義され、ID は安定した文字列であり、
nullが重要な場合を除いて正規化済みモデルでは.optional()を優先している - 最初に増分同期を選択しており、ドキュメントまたはペイロードに基づいて全件更新が明確に正当化されている場合を除き、チェックポイントスキーマを使用している
-
nango.getCheckpoint()を最初に読み取り、各ページまたはバッチの後にnango.saveCheckpoint()を実行している - チェックポイントデータによってプロバイダーへのリクエストまたは再開状態(
since、updated_after、cursor、page_token、offset、page、since_idなど)が変化する - 変更分のみを取得するチェックポイント同期(
modified_after、updated_after、変更レコードのエンドポイント)では、trackDeletesStart()/trackDeletesEnd()を使用していない - チェックポイントを使用していない場合、実行可能なチェックポイント戦略が存在しない理由を回答で正確に説明している
- 生のプロバイダースキーマで省略と
nullを正しくモデル化し、フィールドではケーシングをそのまま維持するか、API の過半数を占めるケーシングを使用している - API が Nango のページネーターに本当に対応できない場合を除き、
nango.paginate()を使用している - プロバイダー API 呼び出しで
retries: 3を使用しており、文書化された例外がない限り、同期のリトライ値は3を超えない - 削除戦略が同期の種類に合致している。増分同期での
batchDelete()はプロバイダーが明示的な削除を返す場合に限り使用する。それ以外では、全件更新へのフォールバックで取得/保存前にtrackDeletesStart()を実行し、取得全体と保存が成功した後にのみtrackDeletesEnd()を実行する - 全件更新同期に
checkpointスキーマがあり、そこからページネーションを再開し、実行時間の上限によってページ 1 からやり直すことがないよう各ページの後にsaveCheckpoint()を呼び出している - 全件更新の
trackDeletesEnd()は、clearCheckpoint()の後、最終ページを完了する実行でのみ呼び出す - 必要な場合はメタデータを処理している
-
index.tsに登録済み -
--validate -e dev --no-interactive --auto-confirmでドライランが成功する -
--validateの実行後、nango dryrun ... --saveにより<sync-name>.test.jsonが生成された -
nango generate:testsを実行済みで、npm testが合格する