Is it possible to have partially federated gateway?
Asked Answered
V

1

8

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?

Veinlet answered 1/8, 2019 at 8:17 Comment(1)
I've found a solution, answer here: https://mcmap.net/q/1356543/-is-it-possible-to-have-partially-federated-gatewayNeutralism
N
5

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
});
Neutralism answered 6/5, 2020 at 13:58 Comment(1)
thats brilliant. I've used this a template for a project i am working on. Works as expected - except when extending an entity. Then it appears the Auth header (Bearer token) is not passes. I get this error ``` "message": "Invalid value \"undefined\" for header \"Authorization\"", "path": [ "_entities", 0 ], "extensions": { "code": "DOWNSTREAM_SERVICE_ERROR", .... ``` Any thoughts?Pooka

© 2022 - 2024 — McMap. All rights reserved.