Upgrade to Pro — share decks privately, control downloads, hide ads and more …

BFFなしでも型を諦めない_APIドキュメントから始めるTypeScript型自動生成.pdf

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →
Avatar for shinya tsuchida shinya tsuchida
June 25, 2026
350

 BFFなしでも型を諦めない_APIドキュメントから始めるTypeScript型自動生成.pdf

Avatar for shinya tsuchida

shinya tsuchida

June 25, 2026

Transcript

  1. 2 © Safie Inc.| ⾃⼰紹介 2 © Safie Inc.| 名前

    ⼟⽥ 真哉 出⾝ 熊本県⽟名市 経歴 2023年4⽉ 新卒1期⽣としてセーフィー株式会社に⼊社 フロントエンドチームに配属され3年ほどして最近はSafie Entranceというプロダク トをフルスタックに開発中 趣味‧特技 バドミントン‧ジョギング 年齢 27歳
  2. 3 © Safie Inc.| 会社紹介 データ蓄積・活用 防犯 顧客分析 店舗内映像 接客映像

    好事例店舗の 分析/共有 現場映像 デジタルツイン 遠隔監視/操作 クラウド録画サービス セーフィー株式会社(Safie Inc.) 社員数 616名(連結∕2026年4⽉1⽇時点) ビジョン 映像から未来を作る 会社名
  3. 4 © Safie Inc.| セーフィーのバックエンド事情  PythonやGoで実装 フロントエンドはTypescriptであるが、型情報の共有が 困難 

    APIドキュメントの形式が乱⽴ SwaggerスキーマやreStructuredText(.rst)形式など が混在し、統⼀的な管理が課題 BFF(Backend For Frontend)ではなくても、型安全にAPIを利⽤したい
  4. 5 © Safie Inc.| Safie APIパッケージ セーフィーの API をフロントエンドから型安全に呼び出すための社内ライブラリ 

    3層構造のクラス設計 通信‧認証‧エンドポイント呼び出しの責務を 分離 サービス層を「型のついた API クライアント」 として薄く保つ  APIドキュメントからの⾃動⽣成 薄く保ったサービス層を数百のエンドポイント 分機械的に量産する ツール名: safieAPICodeGenerator
  5. 6 © Safie Inc.| 3層構造 3層構造にしたことによる恩恵  横断的関⼼事の共通化 認証‧XSRF‧タイムゾーン‧ case

    変換を上の層に集約  テスト容易性 通信層は interface 経由で DI モックを差し込むだけ  サービス層が極端に薄い テンプレート同然 → ⾃動⽣成と相性が良い 層 役割 通信層 HTTP 共通処理を担う(axiosの設定とか)。interface で切ってあるのでテスト時はモックに差し替え可能 ベース層 API バージョンごとのベースクラス。認証‧XSRF‧タイムゾーンなど API バージョン共通の前処理を吸収 サービス層 ベース層を継承して、各エンドポイントに対応するメソッドだけを並べる。1 エンドポイント = 1 メソッド
  6. 7 © Safie Inc.| 3層構造 export class AppV1CamerasServiceClient extends AppV1RequestClient

    implements AppV1CamerasService { /** * @description カメラの一覧を返します * @docs https://internal-api-docs.example.com/webapi/app-v1/cameras/list.html */ async fetchAppV1Cameras( params: ReqObjAppV1FetchCameras, ): Promise<ResObjAppV1FetchCameras> { return await this.get<ResObjAppV1FetchCameras>({ url: "/app/v1/cameras", params: params, }); } }
  7. 9 © Safie Inc.|9 © Safie Inc.| コード⾃動⽣成ツール: safieApiCodeGenerator セーフィーはマイクロサービスがいくつもあり、エンドポイントは100個以上存在する

    ⼿書きでやろうとすると次の問題が⽣じる  命名揺れ fetchUserList / listUsers...  写経ミス 名前の綴りやurlなどのtypo に気づかない safieApiCodeGeneratorというTypescript⾃作ツールを使⽤ STEP 1 PlaywrightでAPIドキュメントを開く STEP 2 HTMLからメタ情報を抽出する STEP 3 テンプレートに流し込んでTypescriptコードを出⼒する
  8. 10 © Safie Inc.| APIドキュメントをPlaywrightで開く セーフィーの API ドキュメントは社内認証付き。 普通の fetch

    では取得できないため、以下の⼿順でアクセスします。 STEP 1Playwright で Chromium を起動 STEP 2ログイン済みの Cookie を注⼊ STEP 3対象の API ドキュメントページに遷移 ⾃動⽣成 Step 1 / 3
  9. 11 © Safie Inc.| HTML からメタ情報を抽出する API バージョンによってドキュメントの HTML 構造が違うため、複数のセレクタを順に試すフォールバックを実装

    命名規則を辞書で機械化する // AppV1 系 let dom = await page.$("section#id2 table tr:nth-child(2) td:nth-child(2)"); // EnterpriseV1 系 dom = await page.$("section#id3 dl dd p"); const PREFIX = { GET: "fetch", POST: "create", PUT: "update", PATCH: "update", DELETE: "delete", }; ⾃動⽣成 Step 2 / 3
  10. テンプレートに流し込んでTypeScriptを出⼒する テンプレートが1個で済むのは、まさにベース層がほぼ全部をやってくれているから。 this.get などを呼ぶだけの薄いコードがエンドポイント数ぶん⾃動で並びます。 © Safie Inc. | 11 export

    const METHOD_TEMPLATE = ` /** * @description {$API_DESCRIPTION} * @docs {$API_DOCUMENT_URL} */ async {$METHOD_NAME}(params: {$REQ_OBJ_NAME}): Promise<{$RES_OBJ_NAME}> { return await this.{$HTTP_METHOD}<{$RES_OBJ_NAME}>({ url: '{$API_PATH}', {$PARAM_KEY_NAME}: params, }) } `; 抽出した情報を下記のテンプレートリテラルに流し込みます ⾃動⽣成 Step 3 / 3
  11. 13 © Safie Inc.|13 © Safie Inc.| ⼿動定義の理由 • 「optionalの表記揺れ」「enumの網羅性」「ネスト

    構造」などがドキュメントによってまちまち。 • TypeScriptの型に落とすには情報が不⾜している。 やりかた • quicktype などのWebツールを活⽤。 • APIレスポンスのサンプル(JSON)から⽣成された 型を⼿動⼊⼒。 export type ReqObjAppV1FetchCameras = { // TODO: 型を定義する }; リクエスト/レスポンスの型本体 ReqObjXxx や ResObjXxx の中⾝(プロパティ)は⾃動では作っていない
  12. 14 © Safie Inc. | 13 クライアント側の使い⽅ エンドポイントが何百個増えようと、呼び出し側のコードはこの形のまま。 「型のついた API

    を、毎回同じ書き⽅で呼ぶことができる」 // サービスのインスタンス化 const cameraService = new AppV1CamerasServiceClient( new AxiosRequestClient({ contentType: 'application/json', axiosConfig: { ... } }) ) // アプリ内での呼び出し方( params に型補完が効く)、resにも型がつく const res = await cameraService.fetchAppV1Cameras({ /* params */ })
  13. © Safie Inc. | 15 まとめ • 3層構造による責務の分離 • APIドキュメントからコード⾃動⽣成

    TypeScriptライブラリとして フロントエンドから型安全にAPI呼び出しを実現