question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Fragment definitions within a graphql document ought to be unique.

See original GitHub issue

This is a rehash of apollo-client#906, introduced again because the new fragment interpolation pattern doesn’t go through the addFragmentsToDocument method that we fixed in apollo-client#913 to remove duplicate fragments.

While a recent change in graphql-tag no longer “warns” when duplicate fragments are in a document, we should probably strip the duplicate fragment from the document altogether in either graphql-tag or apollo-client since this will through errors when getting parsed on the server. Optionally we could consider stripping duplicate fragment definitions from the document altogether; although in the aforementioned commit, @tmeasday says

Note that we are simply checking fragment strings for equality, not ensuring that fragment definitions within the larger graphql document have exact equality. We could do the above, but it’d be quite a bit more complicated, and I’m not sure if there’s much benefit. AFAICT the main reason for wanting that before was exactly this functionality.

Steps to Reproduce

Interpolating multiple fragments into the same document generates an invalid GraphQL document:

query {
   ...SomeFragment
}
${SomeFragment}
${SomeFragment}

generates a document like

query {
  ...SomeFragment
}
fragment SomeFragment on SomeResource {
  field
}
fragment SomeFragment on SomeResource {
  field
}

which is invalid (and a server may choke on an invalid GraphQL doc).

I filed this here instead of in apollo-client as the related commit I mentioned above asks why there’d be a benefit to de-duplicating fragments within the document, but this happens more often when the same fragment gets interpolated into the same document twice from different places in the query, not necessarily that the fragment itself is already defined in the document.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
jameswysecommented, Feb 3, 2017

I ran in to this issue as well and threw together a quick workaround:

// schema/utils.js
const requireFragment = require.context('schema/fragments', true, /\.(graphql|gql)$/);
const requireQuery = require.context('schema/queries', true, /\.(graphql|gql)$/);
const requireMutation = require.context('schema/mutations', true, /\.(graphql|gql)$/);

export function removeDuplicateFragments (doc) {
  const usedFragments = {};

  doc.definitions = doc.definitions.filter(def => {
    const included = def.kind !== 'FragmentDefinition' || !usedFragments[def.name.value];
    if (included) {
      usedFragments[def.name.value] = true;
    }
    return included;
  });

  return doc;
}

export function getQuery (name) {
  const doc = requireQuery(`./${name}.gql`);
  return removeDuplicateFragments(doc);
}

export function getFragment (name) {
  const doc = requireFragment(`./${name}.gql`);
  return removeDuplicateFragments(doc);
}

export function getMutation (name) {
  const doc = requireMutation(`./${name}.gql`);
  return removeDuplicateFragments(doc);
}

With a directory structure like:

schema
├── utils.js
├── fragments
│   ├── foo.gql
│   ├── bar.gql
│   ├── baz.gql
├── mutations
│   ├── createFoo.gql
│   ├── createBar.gql
│   ├── createBaz.gql
├── queries
│   ├── someQuery.gql
│   ├── anotherQuery.gql

I can then do @graphql(getQuery('someQuery')) instead of importing directly. Hope it helps 😃

1reaction
czertcommented, Jan 25, 2017

This is still an issue when using graphql-tag/loader and the new #import feature. If a query uses two fragments, both of which #import a third fragment, this third fragment will end up duplicated in the resulting document.

I saw that this was mentioned in PR #28. If you can point me in the right direction, I’d be happy to work on deduplication in the webpack loader.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fragments - Apollo GraphQL Docs
A GraphQL fragment is a piece of logic that can be shared between multiple queries and mutations. Every fragment includes a subset of...
Read more >
GraphQL specification
Fragments can be defined inline within a selection set. This is done to conditionally include fields based on their runtime type. This feature...
Read more >
GraphQL fragments explained
A fragment consists of three unique components: Name: This is the unique name of the fragment (each fragment can have its own name)...
Read more >
GraphQL Directives
Even though fragments declare provided variables in argumentDefinitions , their parent cannot pass provided variables through @arguments . An argument ...
Read more >
Unleash the power of Fragments with GraphQL Codegen
Colocate GraphQL documents with the component code. ... can only access the data defined in it's fragment definitions in order to keep the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found