mcpField
A
adopting-generated-api-types

adopting-generated-api-types

github.com/posthog開発40.5k173 回インストール今日更新
リポジトリ

adopting-generated-api-types について

PostHog のフロントエンド開発者向けスキルです。手書きの API 呼び出しと型を、生成された TypeScript の関数や型に移行する手順を案内します。互換性の確認と検証方法も扱います。

主な機能

  1. 013 種類の手書き API 呼び出しの特定
  2. 02生成関数と型の検索
  3. 03互換性確認と呼び出しの置換
  4. 04旧型の削除と検証

活用シーン

  1. 01旧式 API リクエストの置換
  2. 02生成されたレスポンス型の採用
  3. 03シリアライザー変更後のフロントエンド整理

インストール

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

$npx skills add https://github.com/posthog/posthog --skill adopting-generated-api-types

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

同梱ファイルreferences/migration-patterns.mdreferences/type-compatibility.md

詳細

生成された API 型の採用

概要

PostHog は、OpenAPI パイプラインを通じて Django シリアライザーから TypeScript API クライアント関数と型を生成します。

Django serializer → drf-spectacular → OpenAPI JSON → Orval → TypeScript (api.ts + api.schemas.ts + api.zod.ts)

生成されたファイルは次の場所にあります。

  • コア: frontend/src/generated/core/api.ts、api.schemas.ts、api.zod.ts
  • プロダクト: products/<product>/frontend/generated/api.ts、api.schemas.ts、api.zod.ts

生成された型は Api サフィックスを使用します (DashboardApi、SurveyApi)。手書きの型は決してこれを使用しません。

このスキルは、手動の API 呼び出しと手書きの型を、生成された同等のものに置き換える手順を案内します。

移行すべき 3 つの手動パターン

レガシーの frontend/src/lib/api.ts (約 6000 行) には 3 つのレイヤーがあり、すべてが移行対象です。

1. 高レベルオブジェクト API (最も一般的)

api オブジェクト上のドメイン固有の便利メソッドです。

api.surveys.get(id)
api.surveys.create(data)
api.dashboards.list()
api.cohorts.update(id, data)
api.actions.create(data)

これらは最も広く使用されているパターンです。すべてのエンティティには、CRUD とカスタムメソッド (例: api.surveys.getResponsesCount()、api.dashboards.streamTiles()) を備えた独自の名前空間があります。

2. 手動 URL を指定する生の HTTP メソッド
api.get<SomeType>(`api/projects/${id}/surveys/`)
api.create<SomeType>(`api/projects/${id}/surveys/`, data)
api.update<SomeType>(url, data)
api.put<SomeType>(url, data)
api.delete(url)
3. ApiRequest ビルダー (流暢な URL 構築)
const url = new ApiRequest().surveys().assembleFullUrl()
const response = await api.get(url)

// or directly:
await new ApiRequest().survey(surveyId).withAction('summarize_responses').create({ data })

3 つのパターンはすべて、可能な場合は生成された関数に置き換えるべきです。

いつ使用するか

  • api.<entity>.<method>() (例: api.surveys.get()) を呼び出すファイルを編集するとき
  • api.get<T>(...)、api.create<T>(...) などを呼び出すファイルを編集するとき
  • new ApiRequest() を使用して URL を構築するファイルを編集するとき
  • API レスポンスの形状のために ~/types から手書きのインターフェースをインポートするファイルを編集するとき
  • バックエンドのシリアライザー改善後にフロントエンドコードをクリーンアップするとき

ステップバイステップのワークフロー

1. 手動呼び出しが何をするかを特定する

既存の呼び出しを見て、次を抽出します。

  • HTTP メソッド — GET、POST、PUT、PATCH、DELETE
  • エンティティとアクション — どのリソース、どの操作か
  • 型パラメーター — レスポンスに使用される手書きの型
2. 生成された同等のものを探す

生成された関数名は {resource}{Action} の命名規則に従います。

surveysList          — GET    /api/projects/{id}/surveys/
surveysCreate        — POST   /api/projects/{id}/surveys/
surveysRetrieve      — GET    /api/projects/{id}/surveys/{id}/
surveysPartialUpdate — PATCH  /api/projects/{id}/surveys/{id}/
surveysDestroy       — DELETE /api/projects/{id}/surveys/{id}/

検索する場所:

  • コアエンドポイント: frontend/src/generated/core/api.ts
  • プロダクトエンドポイント: products/<product>/frontend/generated/api.ts

検索戦略:

  1. 生成された api.ts ファイル内でエンティティ名を grep する
  2. get*Url ヘルパー関数で検索する — すべての生成された関数には、その上に URL ビルダーがあります
  3. api.schemas.ts で Api サフィックス付きの型名を検索する

生成された関数が存在しない場合、バックエンドエンドポイントに @extend_schema または @validated_request が欠けている可能性があります。まず improving-drf-endpoints スキルを使用してバックエンドを修正し、その後 hogli build:openapi を実行します。

カスタムアクション (api.surveys.summarize_responses() など) は、バックエンドの @action に @extend_schema が欠けている場合、生成された同等のものを持たないことがあります。まず生成されたファイルを確認し、存在しない場合はバックエンドを修正します。

3. 型の互換性を確認する

手書きの型と生成された Api 型を比較します。主な違い:

  • readonly 修飾子 — 生成された型は読み取り専用フィールドをマークします
  • オプション vs 必須 — 生成された型は required= を正確に反映します
  • Null 許容性 — null 型は明示的です
  • 追加フィールド — 生成された型には、手書きの型が省略しているフィールドが含まれる場合があります

詳細は type-compatibility.md を参照してください。

4. 呼び出しを置き換える

以下を網羅した詳細な before/after の例については、migration-patterns.md を参照してください。

  • 高レベルオブジェクト API (api.surveys.get() → surveysRetrieve())
  • 生の HTTP メソッド (api.get<T>(url) → 生成された関数)
  • ApiRequest ビルダー → 生成された関数
  • ページネーションされたリスト呼び出し
  • リクエストボディを伴う作成/更新
  • 削除呼び出し
  • Kea ロジックのローダーとリスナー
  • abort シグナルを伴う呼び出し
5. 使用箇所で型を置き換える

下流の参照を手書きの型から生成された型に更新します。

// Before
function renderSurvey(survey: Survey): JSX.Element { ... }

// After
function renderSurvey(survey: SurveyApi): JSX.Element { ... }
6. 不要になった型をクリーンアップする

手書きの型のすべての使用箇所を移行した後:

  1. ~/types またはローカルファイルから型定義を削除します
  2. 未使用のインポートを削除します
  3. pnpm --filter=@posthog/frontend typescript:check を実行して、破損がないことを確認します

判断ガイド

シナリオ対応
生成された関数が存在する手動呼び出しを生成された関数に置き換える
生成された型は存在するが、関数は存在しない手動呼び出しのジェネリックパラメータとして生成された型を使用し、@extend_schema を追加するフォローアップを起票する
どちらも存在しない手動パターンを維持し、先にバックエンドのシリアライザー/ビューセットを修正する
生成された等価物がないカスタムアクションapi.<entity>.<method>() 呼び出しを維持し、先にバックエンドの @action アノテーションを修正する
生成された型が手書きのものと異なる形状を持つ呼び出し箇所を生成された形状に適応させる — シリアライザーが信頼できる唯一の情報源です
コードがレスポンスオブジェクトを変更するローカルの可変コピーを使用します: const mutable = { ...response } を作成し、それを変更します
読み取り用と書き込み用の両方の型が必要読み取りには FooApi を使用し、書き込み用の型は Parameters<typeof fooCreate>[1] 経由で導出するか、PatchedFooApi を使用します

インポートの規約

// Core generated functions — import from api.ts
import { domainsList, domainsCreate, domainsRetrieve } from '~/generated/core/api'

// Core generated types — import type from api.schemas.ts
import type { OrganizationDomainApi } from '~/generated/core/api.schemas'

// Core generated Zod schemas — import from api.zod.ts
import { DomainsCreateBody } from '~/generated/core/api.zod'

// Product generated functions — NO tilde prefix, use 'products/' path
import { surveysList, surveysRetrieve } from 'products/surveys/frontend/generated/api'
import type { SurveyApi } from 'products/surveys/frontend/generated/api.schemas'
import { SurveysCreateBody } from 'products/surveys/frontend/generated/api.zod'

// Within a product, relative imports also work
import { logsAlertsCreate } from '../generated/api'
import type { LogsAlertConfigurationApi } from '../generated/api.schemas'
import { LogsAlertsCreateBody } from '../generated/api.zod'

パスのルール:

  • コア: ~/generated/core/... (チルダプレフィックス)
  • 外部からのプロダクト: products/<product>/frontend/generated/... (チルダなし)
  • 内部からのプロダクト: 相対パス ../generated/... または ./generated/...

適切なツリーシェイキングを有効にするために、型には import type を使用します。

生成された関数の内部動作

生成された関数は、api-orval-mutator.ts を介して同じ api モジュールをラップします:

surveysList(projectId, params)
  → apiMutator(url, { method: 'GET' })
    → api.get(url)

生成された関数に切り替えても HTTP の動作は変わりません — 同じ Cookie、同じ CSRF、同じエラーハンドリングです。唯一の違いは型安全性と URL の構築です。

移行の検証

  1. TypeScript チェック: pnpm --filter=@posthog/frontend typescript:check
  2. 残った手動型を grep で検索: コードベース全体で古い型名を検索します
  3. 関連するテストを実行: hogli test <test_file>

関連

  • バックエンド側: 不適切な型を生成するシリアライザーを修正するには improving-drf-endpoints を使用します
  • 型システムのドキュメント: docs/published/handbook/engineering/type-system.md
  • API ミューテーター: frontend/src/lib/api-orval-mutator.ts
  • 型を再生成: hogli build:openapi

コメント