"There can be only one fragment named ~" エラーの対処法

目次

はじめに

GraphQL Code Generator で生成された query で "There can be only one fragment named Fragment" エラーが発生した場合の対処法を解説します。
( @graphql-codegen/cli@2.16, @graphql-codegen/client-preset@1.2 を使用しています)

背景

とあるプロダクトでドキドキしながら GraphQL で通信するフロントエンドと BFF を初めて結合して動作確認してみたとき、BFF から下記のようなエラーが返ってきて結果が返りませんでした。
{"errors":[{"message":"There can be only one fragment named \"AFragment\".","locations":[{"line":99,"column":1}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}

原因

原因は 1 つのリクエストに同じ命名の fragment が複数存在したためでした。
該当の query はこのように書いています。GraphQL Code Generator の client-preset (いわゆる fragment colocation) を活用しており、それぞれの Fragment は子コンポーネントに記載してあります。
query Query {
  aaa {
    id
    ...AFragment
    ...BFragment
  }
}
しかし、GraphQL Code Generator で生成して実際に送信された query は下記の通りになっていました。
query Query {
  sources {
    id
    ...AFragment
    ...BFragment
  }
}

fragment AFragment on Source {
  id
  bbb
}

fragment BFragment on Source {
  id
  ...AFragment
}

fragment AFragment on Source {
  id
  bbb
}
ここで、 AFragment が重複しているためエラーが発生したのだと推測できます。

対処方法

BFragment で参照している AFragment と、 Query で参照している AFragment は同じものなのですが、 GraphQL Code Generator が生成する際、fragment の参照を発見するたびに末尾に fragment をコピーする仕様であるため発生しています。
fragment not deduplicated by `client` preset · Issue #8670 · dotansimha/graphql-code-generator
https://github.com/dotansimha/graphql-code-generator/issues/8670
コンポーネント駆動開発 + fragment colocation のモデルを採用しており、1 回のリクエストで同じ Fragment を複数回参照することは避けられないため、設定変更で回避する必要があります。
GraphQL Code Generator における TypeScript Operations の設定を変更します。
schema: "../graphql/**/*.graphqls"
documents: 
- "src/**/*.{ts,tsx}"
generates: 
  ./src/generated/gql/: 
    preset: "client"
    config: 
      dedupeFragments: true
dedupeFragments: true を設定することで、二階層目以上の Fragment の中身がすべて一階層目の Fragment に集約されるため、結果として重複した Fragment が作られなくなります。
typescript-operations – GraphQL Code Generator
https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations
graphql-codegen を実行して自動生成コードを更新することで問題が解決します。

シェア

Twitter
Facebook
はてブ
LinkedIn
LINE
Pocket