📚

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

2023/03/27に公開約2,200字

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

ログインするとコメントできます