Skip to content

palshin/apollo-link-fragment-first

Repository files navigation

apollo-link-fragment-first

en ru

Apollo Link to extract the query result from a fragment.

Let's say we get a list of users with their posts somewhere in the application:

query USERS_ALL_WITH_POSTS {
  users {
    id
    posts {
      id
      name
    }
  }
}

And in another place we want to get the name of the post by its id:

query POST_ONE($id: ID!) {
  post(id: $id) {
    id
    name
  }
}

Information about the relationship between the results of the USERS_ALL_WITH_POSTS and POST_ONE queries cannot be obtained from the types (or, in other words, the logic of fetching data for POST_ONE is known only to the server, and Apollo can only assume whether there is data in the cache or not). Therefore, in this case, Apollo will make a request to the server, despite the fact that the data for the request has already been loaded into the cache. The package allows you to solve this problem by specifying the desired fragment in the context of the request.

How to use

To start, connect the link to the ApolloClient instance:

import { ApolloClient, ApolloLink, HttpLink, InMemoryCache } from '@apollo/client/core'
import gql from 'graphql-tag';
import FragmentFirstLink from 'apollo-link-fragment-first';

const cache = new InMemoryCache();
const link = ApolloLink.from([
  new FragmentFirstLink(),
  // ...
  new HttpLink({
    uri: 'http://remote.address/graphql',
  }),
])
const apolloClient = new ApolloClient({
  link,
  cache,
});

Now in the request for Apollo in the context option, you can pass a fragment that corresponds to the result of the request:

const POST_FRAGMENT = gql`
  fragment post on Post {
    id
    name
  }
`;

apolloClient.query({
  query: gql`
    query POST_ONE($id: ID!) {
      post(id: $id) {
        ...post
      }
    }
    ${POST_FRAGMENT}
  `,
  variables: {
    id: 1
  },
  context: {
    fragmentFirst: {
      id: `Post:1`,
      fragment: POST_FRAGMENT,
    }
  }
})

If the Apollo cache already contains data for the fragment in fragmentFirst, the link will abort the request and write the fragment data to the cache, in the result of the request POST_ONE.

Vue Apollo

Everything is exactly the same as in the case of using it directly through the ApolloClient instance. But since Vue Apollo turns context into a computed property, we can use the component data to calculate the fragment's id:

export default {
  name: 'PostCard',
  props: {
    id: {
      required: true,
      type: String,
    },
  },
  apollo: {
    post: {
      query: gql`
        query POST_ONE($id: ID!) {
          post(id: $id) {
            ...post
          }
        }
        ${POST_FRAGMENT}
      `,
      variables() {
        return {
          id: this.id,
        };
      },
      context() {
        return {
          fragmentFirst: {
            id: `Post:${this.id}`,
            fragment: POST_FRAGMENT,
          },
        };
      },
    },
  },
}