Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have partially federated gateway?

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?

like image 614
Ville Avatar asked Aug 01 '19 08:08

Ville


1 Answers

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
});
like image 108
linguamachina Avatar answered Sep 21 '22 15:09

linguamachina