8月14日、Steef-Jan Wiggersが「LLM-Generated GraphQL Mocks Arrive at Airbnb and Expedia, While the Spec Lags Behind」と題した記事を公開した。この記事では、AirbnbとExpediaがLLMを活用してGraphQLモックデータを自動生成する仕組みをそれぞれ独自に実装した事例が紹介されている。注目すべきは、6ヶ月間で3つの非互換な実装が乱立しているという事実だ。仕様策定が追いつかない中、GraphQLの「スキーマ=仕様書」という構造的な強みが再現性問題を内包したまま先行実装として走り出している。
「スキーマが仕様書そのもの」という逆転の発想
GraphQLモック生成にLLMを使うアイデアの核心は、「GraphQLのセレクションセットはすでに仕様書である」という観点にある。Expedia GroupのソフトウェアエンジニアSamuel Vazquezは、この利点を生成AIの典型的な失敗モードの裏返しとして説明している。LLMはデータの「形(スキーマ)」を発明するのは苦手だが、決まった形を埋めるのは得意であり、GraphQLスキーマはその「形」をタダで与えてくれる。
これまでの課題は現実的だ。開発者が200行のJSONフィクスチャを手書きしても、翌朝のスキーマ変更で無効になる。この問題への対処として、6ヶ月間で3つの独立したアプローチが登場した。しかし後述するように、3者はディレクティブの位置・引数名・ネットワーク動作のいずれも互換しておらず、今どれかを「標準」として採用することはベンダー固有の解釈を選ぶことを意味する。
Expediaのアプローチ:mockql-rs
Expediaはmockql-rsをオープンソースで公開した(GitHubリポジトリ)。Rust製CLIツールで、リクエスト時にLLMへ問い合わせ、GraphQLのモックレスポンスをリアルタイム生成する。
仕組みはクライアントとサーバーの間にスタンドアローンプロセスとして挟み込む形だ。開発者は未実装フィールドに@mockディレクティブとオプションのヒントを付けるだけでよい。ツールは内部でapollo-compilerを使ってオペレーションをスキーマに対してパース・検証し、モック対象のフィールドと実フィールドを分離。実フィールドは上流のサーバーに転送し、モック対象はLLMにプロンプトを投げ、両者のレスポンスをマージして返す。
query TripDetails($id: ID!) {
trip(id: $id) {
property {
name
address
}
recommendations @mock(hint: "5 most popular nearby restaurants") {
title
description
distance
}
}
}
property(ホテル名・住所)は実バックエンドから、recommendations(レストラン候補)はLLMが生成する。レスポンスは両者が同じペイロードに混在する。
{
"data": {
"trip": {
"property": {
"name": "Hotel Palazzo Pischedda",
"address": "Via Roma, 09089 Bosa OR, Italy"
},
"recommendations": [
{
"title": "Ristorante Sa Pischedda",
"description": "Located directly at the hotel, famous for authentic Sardinian seafood.",
"distance": "0.0 miles"
},
{
"title": "Locanda di Corte",
"description": "Charming restaurant in the historic medieval center.",
"distance": "0.3 miles"
}
]
}
}
}
このマージ構造は開発者視点での透過的な統合を意図したものだが、クライアントコード上でどのフィールドが実データでどのフィールドがLLM生成かを区別する手段はない。デバッグ時や障害調査時には注意が必要で、ログやメタデータで出所を追跡する仕組みを別途用意することが推奨される。
CLIという形態を選んだのは、テストランナー・CIジョブ・ビルドスクリプトからプロセスとして呼び出せるため、SDK依存を排除できるという理由からだ。
Airbnbのアプローチ:ビルド時生成
Airbnbは4月に別のアプローチを公開した。@generateMockディレクティブをコード生成ツール「Niobe」(関連ブログ記事)のビルド時に処理し、JSONモックファイルと型付きアクセサ関数を両方生成する。デモアプリ・スナップショットテスト・ユニットテストでの利用を想定しており、再生成時に開発者の手動編集を意図的に保持する点が特徴だ。
GraphQL Foundation RFCは第三の立場
GraphQL Foundation RFC(2月公開)はさらに異なる設計を取る。@mockをフィールドではなくオペレーション単位で定義し、name引数で複数の名前付きレスポンスを切り替える。モックデータはソースファイルに隣接する__graphql_mocks__ディレクトリに配置し、クライアントはモックが有効なとき一切ネットワークリクエストを発行しないことが仕様上の要件となっている。
LLM生成はあくまで推奨戦略として言及されるのみで、必須の仕組みではない。RFCはさらにコーディングエージェントへの対応も先取りしており、エージェントがモックを会話形式で追加・修正できるAgent Skillの実装を推奨し、SKILL.mdのサンプルも含まれている。
3アプローチの核心的な違い
3つのアプローチはいずれも「GraphQLスキーマを制約として使う」という発想を共有しながら、設計判断は大きく異なる。特に再現性とネットワーク透過性の扱いが分岐点だ。
Expedia mockql-rs |
Airbnb | GraphQL RFC | |
|---|---|---|---|
| 生成タイミング | リクエスト時 | ビルド時 | 任意(LLMは推奨のみ) |
@mockの位置 |
フィールド | フィールド | オペレーション |
| ネットワーク | 実データとマージ | なし | 一切発行しない |
| 再現性 | 非決定的 | 決定的(ファイル保存) | 決定的(ファイル保存) |
技術的に重要な問題は再現性だ。Expediaの方式は実行ごとに新たなデータを生成するため文脈的な整合性は高いが、スナップショットテストが前提とする「同じ入力に同じ出力」という性質を持たない。非決定的なフィクスチャがCIでどう機能するかは、どちらの記事も言及していない。
さらに注意すべき点として、RFCは現在Stage 0(ストローマン段階)であり、チャンピオン(推進者)も未定だ。これはGraphQL仕様プロセスの最初期段階であり、進展の保証はない。Expediaの実装はディレクティブの位置・引数名・ネットワーク動作のいずれもRFCと異なるため、今@mockを標準として採用することは、仕様が同じ名前を別の意味で使っている特定ベンダーの解釈を採用することを意味する。
なぜRESTではなくGraphQLで先に実用化されたのか
比較表が示す違いを踏まえると、より根本的な問いが浮かび上がる。このパターンがRESTではなくGraphQLで先に現れた理由だ。スキーマで形が規定された出力は、LLMが生成したデータを「それらしいノイズ」ではなく「使えるデータ」にする制約であり、同時に生成データがクエリとずれたことを検出できる根拠にもなる。REST APIにはこの「形」が仕様として存在しないか、あってもOpenAPI仕様の普及率にばらつきがあるため、同様のアプローチが成立しにくい。
これが仕様として統一されるか、3つの非互換な実装として分岐するかは、現時点では未解決のままだ。
詳細はLLM-Generated GraphQL Mocks Arrive at Airbnb and Expedia, While the Spec Lags Behindを参照していただきたい。