📚

【GraphQL】 There can be only one fragment エラーの対処法

2023/03/27に公開

GraphQL Code Generatorを用いたfragmentを含んだクエリで "There can be only one fragment" エラーが発生した場合の対処法を解説します。

( @graphql-codegen/cli@2.16, @graphql-codegen/client-preset@1.2 を使用しています)

背景

とあるプロダクトでドキドキしながらGraphQLで通信するフロントエンドとBFFを初めて結合して動作確認してみたとき、BFFから "There can be only one fragment" エラーが返ってきてしまいました。

Response
{
  "errors": [
    {
      "message": "There can be only one fragment named \"AFragment\".",
      "locations": [{ "line": 99, "column": 1 }],
      "extensions": { "code": "GRAPHQL_VALIDATION_FAILED" }
    }
  ],
  "data": null
}

該当のqueryはこのように書いています。GraphQL Code Generatorのclient-presetを活用しており、それぞれのFragmentは子コンポーネントに定義してあります。

Example.tsx
import { graphql } from "@/libs/gql";

const query = graphql`
  query Query {
    examples {
      id
      ...AFragment # 子コンポーネントにて定義
      ...BFragment # 子コンポーネントにて定義
    }
  }
`;

原因

原因は1つのリクエストに同じ命名のfragmentが複数存在したためでした。

GraphQL Code Generatorで生成して実際に送信されたqueryは次の通りになっていました。

Request
query Query {
  examples {
    id
    ...AFragment
    ...BFragment
  }
}

fragment AFragment on Example {
  id
  name
}

fragment BFragment on Example {
  id
  ...AFragment
}

fragment AFragment on Example {
  id
  name
}

ここで、 AFragment が重複しているためエラーが発生したのだと推測できます。

対処方法

BFragment で参照している AFragment と、 Query で参照している AFragment は同じものなのですが、 GraphQL Code Generatorが生成する際、fragmentの参照を発見するたびに末尾へfragmentをコピーする仕様であるため発生しています。

https://github.com/dotansimha/graphql-code-generator/issues/8670

コンポーネント駆動開発 + Fragment Colocation (Fragment Masking) のモデルを採用しており、1回のリクエストで同じFragmentを複数回参照することは避けられないため、設定変更で回避することにしました。

GraphQL Code GeneratorにおけるTypeScript Operationsの設定を変更します。

codegen.yml
schema: "../graphql/**/*.graphqls"
documents:
  - "src/**/*.{ts,tsx}"
generates:
  ./src/generated/gql/:
    preset: "client"
    config:
      dedupeFragments: true

dedupeFragments: true を設定することで、二階層目以上のFragmentの中身がすべて一階層目のFragmentへ集約されるため、結果として重複したFragmentが作られなくなります。

https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations

graphql-codegen を実行して自動生成コードを更新することで問題が解決します。

まとめ

GraphQL Code Generatorでfragmentを使う際には、 dedupeFragments: true を設定するようにしましょう。

client-presetは最高の開発体験だったので、また別の機会にご紹介します。

Discussion