DEV Community

CodeNameGrant
CodeNameGrant

Posted on

Multiple GraphQL Endpoints with Apollo Client

If you are knee-deep in the world of web development, chances are you have crossed paths with GraphQL and Apollo Client. This dynamic duo has revolutionized how developers interact with data on the frontend. However Apollo Client does have a flaw, "How do I connect to multiple GraphQL endpoints using a single client instance? This post will explain a few ways to achieve just that.

Note: For the sake of brevity, 'query' will refer to any GraphQL operation; Query, Mutation or Subscription.

ApolloLink.split()

The native approach is to make use of the split function provided by the @apollo/client. This will enable your link chain to branch to one of two HttpLinks based on the result of a boolean check.

import { ApolloClient, ApolloLink, HttpLink } from '@apollo/client';

const endpoint1 = new HttpLink({
  uri: 'http://endpoint1.com/graphql',
  ...
});

const endpoint2 = new HttpLink({
  uri: 'http://endpoint2.com/graphql',
  ...
});

const client = new ApolloClient({
  link: ApolloLink.split(
      operation => operation.getContext().apiName === 'end1', // boolean check
      endpoint1, // if true
      endpoint2  // if fa
  )
  ...
});

// pass the apiName via the context in your Query
useQuery(QUERY, { variables, context: { apiName: 'end1' } });
Enter fullscreen mode Exit fullscreen mode

In this example, the boolean check is based on a context variable, however the test can be anything. The split function is simple to implement but is limited to only two GQL connections.

Dynamic HttpLink

But now what if a application serves as the frontend for a suite of microservices? Well, by expanding the use of the operation context the endpoint in the HttpLink can be set dynamically.

import { ApolloClient, createHttpLink } from '@apollo/client';

const httpLink = createHttpLink({
  uri: ({ getContext }) => {
    const { apiName } = getContext();

    if (apiName === 'end1') return 'http://endpoint1.com/graphql';
    if (apiName === 'end2') return 'http://endpoint2.com/graphql';
    if (apiName === 'end3') return 'http://endpoint3.com/graphql';
    ...
  }
});

const client = new ApolloClient({
  link: httpLink
  ...
});

// pass the apiName via the context in your Query
useQuery(QUERY, { variables, context: { apiName: 'end1' } });
useQuery(QUERY, { variables, context: { apiName: 'end2' } });
Enter fullscreen mode Exit fullscreen mode

This solution is also relatively simple and allows for expendability as new microservices are added to the suite that the client app has to connect to.

The disadvantage of both of these approaches is that the developer has to include the apiName in the context every time that useQuery. Personally I found this approach lead to a messy implementation. I mean declaring the context object on every request is so repetitive.

Apollo MultiAPILink

I wanted a solution that was more intuitive though, something that removed the need to declare the API every time a useQuery was used, enter @habx/apollo-multi-endpoint-link. This library allows the API to be declared on the GQL query as a directive, instead of every time useQuery is called.

const QUERY1 = gql`
  query Users @api(name: end1) {
    users { id name }
  }
`;

const QUERY2 = gql`
  query Companies @api(name: end2) {
    companies { id name code }
  }
`;
Enter fullscreen mode Exit fullscreen mode

The @api(name: end1) informs the library which endpoint to use based on configuration.
Note: The directive is removed from the query before it is sent to the server.

import { ApolloClient, createHttpLink } from '@apollo/client';
import { MultiAPILink } from '@habx/apollo-multi-endpoint-link';

const multiHttpLink = new MultiAPILink({
  endpoints: {
    end1: 'http://endpoint1.com',
    end2: 'http://endpoint2.com',
    end3: 'http://endpoint3.com',
    ... 
  },
  createHttpLink: () => createHttpLink()
});

const client = new ApolloClient({
  link: multiHttpLink
  ...
});

// Now use the query without any additional api config
useQuery(QUERY1);
useQuery(QUERY2);
Enter fullscreen mode Exit fullscreen mode

The MultiAPILink matches the API name with the relevant endpoint. Since the API is declared on the query, it doesn't have to be repeated in every useQuery, leaving code much cleaner and containing less duplication.

Conclusion

In summary, its definitely possible to have multiple endpoints in a single Apollo Client instance.

Sources

Github: @habx/apollo-multi-endpoint-link
Apollo Link Overview
Apollo Link - Directional Composition

Top comments (0)