View on GitHub

Imagine this, you spent day and night working on the perfect web application. You worked together with the backend devs to craft the smoothest and most stable GraphQL endpoint there ever was. Filtering, sorting, paging, all the parts were there. New collection? No problem at all, it's added in no-time. Amazing! Until... It was decided to add a second GraphQL endpoint. Wait what, can't we add it as a collection to the current endpoint? No? But wait, we can do schema stitching, right? Right??

Well the answer was no. Here we are with 2 GraphQL endpoints that both need to be consumed simultaneously. We're using Apollo Client, which by default only supports a single endpoint. Next to that, we're also using the GraphQL Code Generator for converting the schema and operations.graphql files to Typescript types and documents. A generic, solid solution was mandatory to support both of these libs, so I went ahead and created a structure that you can also reuse in your projects.

Used endpoints

I created a demo application on GitHub. In this demo I consumed data from a free-to-use SpaceX GraphQL endpoint and a countries GraphQL endpoint.

Consumption of data

First I want to show what I ended up with on the consumption part of the application.

const { data: launchesData, loading: launchesLoading } = useSpacexQuery(GetLaunchesDocument, {
  variables: {
    limit: 5
  }
});

const { data: countriesData, loading: countriesLoading } = useCountriesQuery(GetCountriesDocument, {
  variables: {
    filter: {
      continent: {
        eq: 'OC'
      }
    }
  }
});

As you can see, instead of the default useQuery hook from Apollo I now have useSpacexQuery and useCountriesQuery hooks. As you can imagine, they both fetch data from their corresponding data source. I made useSpacexMutation and useCountriesMutation available as well, I just don't use them in this example.

Setting up Apollo clients

In useApollo.ts I made the hooks available. What I basically do, is create a generic instance of useQuery and inject the correct Apollo Client based on whether you want SpaceX data or Countries data.

const useGenericQuery =
  (type: ApolloClientTypes) =>
  <TData = any, TVariables extends OperationVariables = OperationVariables>(
    query: DocumentNode | TypedDocumentNode<TData, TVariables>,
    options?: QueryHookOptions<TData, TVariables>
  ) => {
    const { getClient } = useApolloClient();
    const client = getClient(type);

    return useQuery(query, {
      ...options,
      client: client
    });
  };
export const useSpacexQuery = useGenericQuery('spacex');
export const useCountriesQuery = useGenericQuery('countries');

In useApolloClient.ts you can see how to return the correct GraphQL endpoint for your data. By creating 2 Apollo Clients (or more if you need them) you can use either of them in your data calls.

Because we created the custom useXQuery hook, we don't ever have to think of configuring the Apollo Client again, we can just use it as easily as when you only had one useQuery hook.

GraphQL Code Generator

I use the GraphQL Code Generator for generating Typescript types and documents based on a schema and operation.grapql files. Usually that works pretty straight forward if you only have a single endpoint. Since I have 2 of them, I simply added 2 codegen.ts files.

My countries codegen.ts file responds to operations.countries.graphql files, and my SpaceX codegen.ts file to operations.spacex.graphql files.

I found this the most straight forward solution to a sub-optimal situation. Hopefully this helps you out as well.

Cheers!