4

I have a GraphQL query like this:

import { gql } from 'apollo-boost';

export default gql`
  {
    pageHomeCollection(limit: 1) {
      items {
        navigationLinkLeft {
          ... on PageBasic {
            slug
            title
          }
          ... on PageShop {
            title
          }
          ... on PostCollection {
            slug
            title
          }
        }
        navigationLinkRight {
          ... on PageBasic {
            slug
            title
          }
          ... on PageShop {
            title
          }
          ... on PostCollection {
            slug
            title
          }
        }
        title
      }
    }
  }
`;

The requested data for both navigationLinkLeft and navigationLinkRight are the same, so I'd like to avoid the duplication. I know about fragments, but not sure if it's possible to extract the 3 ... on because I'm not sure what type the fragment would be. Is this possible?

CaribouCode
  • 13,998
  • 28
  • 102
  • 174
  • Does this answer your question? [Using GraphQL Fragment on multiple types](https://stackoverflow.com/questions/48940240/using-graphql-fragment-on-multiple-types) – Eldar Jan 04 '20 at 11:28

1 Answers1

8

Yes, you can nest fragments. Assuming navigationLinkLeft and navigationLinkRight have the same type, you can do something like this:

{
  pageHomeCollection(limit: 1) {
    items {
    navigationLinkLeft {
      ...YourFragment
    }
    navigationLinkRight {
      ...YourFragment
    }
    title
  }
}

fragment YourFragment on SomeInterfaceOrUnionType {
  ... on PageBasic {
    slug
    title
  }
  ... on PageShop {
    title
  }
  ... on PostCollection {
    slug
    title
  }
}

If navigationLinkLeft and navigationLinkRight do not have the same type, this won't work. At best, you can only avoid duplicating the fields themselves:

{
  pageHomeCollection(limit: 1) {
    items {
    navigationLinkLeft {
      ...NavigationLinkLeftFragment
    }
    navigationLinkRight {
      ...NavigationLinkRightFragment
    }
    title
  }
}

fragment NavigationLinkLeftFragment on PageHomeNavigationLinkLeft {
  ...PageBasicFragment
  ...PageShopFragment
  ...PostCollectionFragment
}

fragment NavigationLinkRightFragment on NavigationLinkRight {
  ...PageBasicFragment
  ...PageShopFragment
  ...PostCollectionFragment
}

fragment PageBasicFragment on PageBasic {
  slug
  title
}

fragment PageShopFragment on PageShop {
  title
}

fragment PostCollectionFragment on PostCollection {
  slug
  title
}

The above avoids using inline fragments, but you can always use an inline fragment if you don't need to reference a fragment by name elsewhere. So you can also just do:

navigationLinkLeft {
  ...PageBasicFragment
  ...PageShopFragment
  ...PostCollectionFragment
}
navigationLinkRight {
  ...PageBasicFragment
  ...PageShopFragment
  ...PostCollectionFragment
}
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • Sorry for the late reply. So I figured you could do this but wasn't sure what `SomeInterfaceOrUnionType` would need to be in this case. Each of the 3 things in the fragment are their own types. – CaribouCode Jan 04 '20 at 16:39
  • @Coop you need to check the schema you're querying to determine what the type is for the `navigationLinkLeft` field. If you didn't write the schema yourself, you can check the docs in GraphiQL or GraphQL Playground, or use introspection. – Daniel Rearden Jan 04 '20 at 16:55
  • Righty. So GraphiQL is telling me the 3 potential datasets on navigationLeftLink are of type `PageHomeNavigationLinkLeft` and the 3 on navigationLinkRight are of type `NavigationLinkRight`. So is it still possible to achieve what I want when the types are different? – CaribouCode Jan 04 '20 at 16:58
  • 1
    @Coop Sorry, I misunderstood your comment. If the types are different, then, no you won't be able to do DRY things up as much. Please see my edit. – Daniel Rearden Jan 04 '20 at 19:31