8
votes

I'd like to federate services, but let the federation gateway also hold own schema and logic that would proxy REST API endpoints for simplicity. Now it looks like I need to have federation gateway service, federated graphql service(s) and the rest<->graphql bridge service separately. Anyhow in our case the rest-graphql gateway could be living in the federation-gateway at least for the time being to avoid unnecessary bootstrapping & maintenance.

Looks like Apollo federation gateway has localServiceList that seemingly serves exactly this purpose. An example config:

const gateway = new ApolloGateway({
    serviceList: [
        { name: "some-service", url: "http://localhost:40001/graph" }
    ],
    localServiceList: [
        { name: "rest-bridge", typeDefs }
    ]
});

But it does not do the trick: If there is localServiceList, it skips the serviceList.

So the question is: Is this possible to hold also own schema & logic in Apollo Federation gateway?

1
I've found a solution, answer here: stackoverflow.com/a/61637093/2748290linguamachina

1 Answers

5
votes

Yes, this can be done:

import { buildFederatedSchema } from '@apollo/federation';
import {
  ApolloGateway,
  LocalGraphQLDataSource,
  RemoteGraphQLDataSource
} from '@apollo/gateway';
import gql from 'graphql-tag';

const localServices = {
  foo: {
    schema: {
      typeDefs: gql`
        // ...
      `,
      resolvers: {
        // ...
      }
    }
  },
  bar: {
    schema: {
      typeDefs: gql`
        // ...
      `,
      resolvers: {
        // ...
      }
    }
  }
};

const remoteServices = {
  baz: {
    url: 'http://baz.local/graphql'
  },
  qux: {
    url: 'http://qux.local/graphql'
  }
};

const services = {
  ...localServices,
  ...remoteServices
};

// By providing a protocol we trick ApolloGateway into thinking that this is a valid URL;
// otherwise it assumes it's a relative URL, and complains.
const DUMMY_SERVICE_URL = 'https://';

const gateway = new ApolloGateway({
  // We can't use localServiceList and serviceList at the same time,
  // so we pretend the local services are remote, but point the ApolloGateway
  // at LocalGraphQLDataSources instead...
  serviceList: Object.keys(services).map(name => ({
    name,
    url: services[name].url || DUMMY_SERVICE_URL
  })),
  buildService({ name, url }) {
    if (url === DUMMY_SERVICE_URL) {
      return new LocalGraphQLDataSource(
        buildFederatedSchema(
          services[name].schema
        )
      );
    } else {
      return new RemoteGraphQLDataSource({
        url
      });
    }
  }
});

const apolloServer = new ApolloServer({
  gateway,
  subscriptions: false
});