Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fragments are no longer deduplicated as of 1.4.0 #403

Closed
good-idea opened this issue Aug 22, 2019 · 3 comments
Closed

Fragments are no longer deduplicated as of 1.4.0 #403

good-idea opened this issue Aug 22, 2019 · 3 comments

Comments

@good-idea
Copy link
Contributor

Describe the bug
When a query string has multiple references to the same fragment, GraphQL servers will return an error like "There can be only one fragment named "LinkFragment"."

When using fragments to compose queries, it's common to use fragments-within-fragments, like so:

/**
 * Fragments
 */
export const linkFragment = /* GraphQL */ `
	fragment LinkFragment on PageLink {
		linkData
	}
`

export const textBlockFragment = /* GraphQL */ `
	fragment TextBlockFragment on TextBlock {
		title
		body
		link {
			...LinkFragment
		}
	}
	${linkFragment}
`

export const imageBlockFragment = /* GraphQL */ `
	fragment ImageBlockFragment on ImageBlock {
		title
		caption
		link {
			...LinkFragment
		}
	}
	${linkFragment}
`

export const contentSectionFragment = /* GraphQL */ `
	fragment ContentSectionFragment on ContentSection {
		items {
			... on ImageBlock {
				...ImageBlockFragment
			}
			... on TextBlock {
				...TextBlockFragment
			}
		}
		backgroundImage {
			...SanityImageFragment
		}
	}
	${imageBlockFragment}
	${textBlockFragment}
`
/**
 * Homepage Query
 */
export const HomepageQuery = /* GraphQL */`
	query HomepageQuery {
		Homepage(id: "homepage") {
			_id
			contentSections {
				...ContentSectionFragment
			}
		}
	}
	${contentSectionFragment}
`

With urql's removal of graphql-tag, these duplicated fragments are not removed from the final query. This can be fixed by using graphql-tag in your project, i.e.:

export const HomepageQuery = gql`
	query HomepageQuery {
		Homepage(id: "homepage") {
			_id
			contentSections {
				...ContentSectionFragment
			}
		}
	}
	${contentSectionFragment}
`

Steps to reproduce

Compose a query like the above that contains multiple inline references to the same fragment

Expected behavior
The query should work as it did before, with urql de-duplicating the fragments. Perhaps an exchange that does something similar to this.
Or, an error message that detects the problem ahead of time and suggests to import and use gql manually.

Actual behavior
Duped fragments are no longer removed, Graphql API complains

@good-idea good-idea added the bug 🐛 Oh no! A bug or unintented behaviour. label Aug 22, 2019
@kitten kitten added question 🙋 and removed bug 🐛 Oh no! A bug or unintented behaviour. labels Aug 22, 2019
@kitten
Copy link
Member

kitten commented Aug 22, 2019

So, this is technically a regression, but due to the fact that we don’t call graphic-tag for you anymore :)

So if you use graphologists-tag you’ll see the same behaviour again.

This was indeed intentional but sorry for not highlighting it in the changelog!

@kitten kitten closed this as completed Aug 22, 2019
@good-idea
Copy link
Contributor Author

Yup, I did find that using gql on my own took care of this. For DX, though, my suggestion of a "fix" for this issue would be either cleaning out the duplicate names, or providing a better warning on how to fix it. I was already familiar enough with graphql-tag to know that it would probably do the trick -- but, otherwise, I would have been scratching my head for a while wondering why my queries weren't working anymore.

It was pretty easy to create an exchange that takes care of this - I'm about to open a WIP PR. If it's something you'd like to include, I'd be happy to clean it up with a little guidance.

@flamerged
Copy link

I get the following errors when executing a query with urql:

[GraphQL] There can be only one fragment named "CourseFull". [GraphQL] There can be only one fragment named "ProductVariantFull". [GraphQL] There can be only one fragment named "ImageFull".

Here is the query:

refetchOrder() {
    const query = gql`
      query CWA_productVariantOrderFindById($id: String!) {
        productVariantOrderFindById(id: $id) {
          ...ProductVariantOrderFull
          isSinglePurchase
          variant {
            ...ProductVariantFull
            product {
              ...ProductFull
              image {
                ...ImageFull
                thumbnails(keys: ["w:740|h:416"]) {
                  ...ImageThumbnailFull
                }
              }
            }
          }
          invitations {
            id
            status
            progress
            customer {
              id
              email
            }
            customerParticipations {
              ...CustomerCourseParticipationFull
              course {
                ...CourseFull
                isCertificateEnabled
              }
            }
          }
          invoice {
            ...CustomerInvoiceFull
          }
        }
      }
      ${PRODUCT_FULL}
      ${COURSE_FULL}
      ${PRODUCT_VARIANT_FULL}
      ${PRODUCT_VARIANT_ORDER_FULL}
      ${CUSTOMER_INVOICE_FULL}
      ${IMAGE_FULL}
      ${IMAGE_THUMBNAIL_FULL}
      ${CUSTOMER_COURSE_PARTICIPATION_FULL}
    `
    return this.$urql
      .query(query, { id: this.$route.params.orderId })
      .toPromise()
      .then(({ data }) => {
        this.order = data.productVariantOrderFindById
      })
  }

We are currently switching from apollo to urql and this exact same query works just fine with apollo but not with urql. I have other queries with the same issue where i can't use nested fragments.

Here are the fragments for reference:

export const PRODUCT_FULL = gql`
  fragment ProductFull on Product {
    id
    name
    isActive
    description
    vatApplication
    image {
      ...ImageFull
    }
    variants {
      ...ProductVariantFull
    }
    courses {
      ...CourseFull
    }
  }
  ${IMAGE_FULL}
  ${PRODUCT_VARIANT_FULL}
  ${COURSE_FULL}

export const COURSE_FULL = gql`
  fragment CourseFull on Course {
    id
    name
    description
    startsAt
    endsAt
    type
    isConfirmCourseCompletionEnabled
    isCourseParticipationRequestEnabled
    courseCompleteConfirmationText
    chargeStatus
    createdAt
    areCommentsAllowed
    commentsAllowedOn
    didCustomerRequestCourseAccess
    isBookmarked
  }
`

export const PRODUCT_VARIANT_FULL = gql`
  fragment ProductVariantFull on ProductVariant {
    id
    name
    externalId
    description
    priceVariant
    unitQuantity
    priceType
    fee
    vatDetail {
      vatPercentage
      vatApplicationType
      netAmount
    }
  }

export const IMAGE_FULL = gql`
  fragment ImageFull on Image {
    id
    width
    height
    file {
      id
      url
      contentType
    }
  }
`

I found this issue saying to use the graphql-tag but it's already in use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants