Can we run Apollo federation along with the monolithic GraphQL server

Hello,
We have a monolithic GraphQL server and now we are trying to migrate to Apollo federation but we want to do one service at a time so we were wondering if we can have a single Apollo server that can serve traffic to both monolithic server and to the federated server.
Federation document does have a section about incremental approach(Introduction to Apollo Federation - Apollo Federation - Apollo GraphQL Docs) but we are not sure if we can have production traffic with an Apollo gateway serving traffic to both instances.

Thanks

If you have native and web apps using the existing monolith, I think the best option is to set up a gateway service with the same endpoint as your monolith, update the schema document in your monolith to use federation architecture (extend type query). With these two pieces in place, your production traffic should now go through the gateway and then hit your monolith (which is now a federated service).

Once you have the above, you can start migrating types/queries from your monolith into different federated services. Here’s a hellpful guide for migrations - Entities - Apollo Federation - Apollo GraphQL Docs

Hi kartik_gujarati!

Thanks for the response, I was hoping not to migrate our entire graph to use federation architecture ( extend type query ). Our graph is quite big so we wanted to migrate only a part of our graph to use federations to see the gains we get from it before we migrate the entire graph. That’s the reason we wanted a way to serve traffic to our monolith and federated service based on the request with the help of gateway or without.

Please let me know if this is something that we can do out of the box.

Thanks

If you want to maintain both federated server and the monolith at the same time, one option I can think of is to setup the federated server gateway with a different endpoint and have the newer versions of your clients talk to the new federated services through gateway’s endpoint while continuing to support older clients through the monolith. You can use a phased rollout or feature flagging approach to safely rollout the switch-over.

Got it, Thanks @kartik_gujarati for all the help.

@Nagarchith_Nama_Bala We recommend having a single endpoint. If you put a Gateway in front of a single existing GraphQL service, you don’t need to use federated features and directives (e.g., extend types are native to GraphQL, but you don’t even need to use them) you should find success and be able to avoid the separate endpoint and be in the best position to start adding new services.

@abernix Thanks for that suggestion but even with a gateway in front of our existing service, I don’t seem to find a way to serve both my legacy/monolith graph and the federated graph at the same time via the gateway. Can you please point me to any documentation that can help me with this? We already have migrated part of our graph over to use federation but we wanted to test it out in production before switching the rest over. During this testing phase we want to run both of our graphs/servers to not cause any issues to our client apps.

1 Like

@abernix We have a similar situation. We’re starting with a very small set of services, and there’s some resistance to adding a network hop (even if on same host) to reach out to a subgraph.

We definitely want to be structured properly for some point down the line when we add more services however, and as a result want to have ourselves set up correctly for Federated Graphs even if initially we’re not federated. – Any thoughts?

If you really really really want to avoid the network hop, you can run a gateway and a monolith GraphQL API in the same process.

import { ApolloGateway, LocalGraphQLDataSource, RemoteGraphQLDataSource } from '@apollo/gateway';

// your current graphql schema
const monolithSchema = makeExecutableSchema({ ... });

const gateway = new ApolloGateway({
  buildService({ name, url }) {
    if (name === 'monolith') {
      return new LocalGraphQLDataSource(monolithSchema);
    } else {
      return new RemoteGraphQLDataSource({ name, url });
    }
  }
}); 

When using managed federation, you can publish your monolith schema as a subgraph. It can be your only subgraph until you start breaking up the monolith.

(This works only if you’re doing everything in JavaScript/TypeScript today, of course.)

That being said, don’t fear the extra network hop! It’s minimal with a well-tuned Node.js server.

3 Likes

@lennyburdette We don’t use managed federations for our graph. I do see any error that our monolith schema does not support federation specifications.

All GraphQL requests will now fail. The startup error was: Couldn’t load service definitions for “monolith” at http://localhost:4000: Cannot query field “_service” on type “Query”.

We use type-graphql(type-graphql/bootstrap.md at master · MichalLytek/type-graphql · GitHub) for our graphs so I updated our schema generation step to

import { makeExecutableSchema } from "graphql-tools";
import { buildTypeDefsAndResolvers } from 'type-graphql';
const { typeDefs, resolvers } = await buildTypeDefsAndResolvers({
   resolvers
 }); 
const schema =  makeExecutableSchema({ typeDefs, resolvers });

// Gateway code
const serviceList = [
    { name: "test", url: 'http://localhost:5000'  },
    { name: "monolith", url: 'http://localhost:4000' },
];

const monolithSchema = await schema();

  const gateway = new ApolloGateway({
    serviceList,
    buildService: ({ name, url }): any => {
      if (name === 'monolith') return new LocalGraphQLDataSource(monolithSchema);
      return new RemoteGraphQLDataSource({ name, url });
    },
  });

We don’t want to migrate our monolith graph to federation specification right now. So let me know if I need to modify something for it to work without a network hop.

Any help will bee much appreciated. Thanks

This is helpful, thanks! If you don’t want to add the federation spec to your monolith schema, or start using managed federation, then you have one more option: static composition with rover.

Instead of using serviceList to have the gateway fetch subgraph schemas and compose them at runtime, you can create a “supergraph schema” with a config file and a command:

subgraphs:
  monolith:
    routing_url: "doesnt matter, this will be a local graphql data source"
    schema: 
      file: monolith.graphql
  test:
    routing_url: http://localhost:5000
    schema:
      file: test.graphql
rover supergraph compose --config config.yaml > supergraph.graphql

Then remove the serviceList argument:

const gateway = new ApolloGateway({
  supergraphSdl: readFileSync('supergraph.graphql', 'utf-8'),
  buildService() { ... }
});

I’d still very much recommend managed federation in production so that the gateway can update to new versions of the subgraph schemas automatically. But this pattern works great in development.

1 Like

@lennyburdette Thanks for that suggestion but looks like rover doesn’t support merging/composing a federated schema with a monolithic schema. I am looking for another library that can help me merge these schemas but haven’t had any luck so far.

error: UNKNOWN: Unknown type “userName”.

We are planning to just go with an additional network hop for now to speed up our development.

That surprises me—I’ve gotten it to compose various kinds of schemas before—but I guess I’d have to see your schemas to debug. But :+1: to using the gateway as intended.

On a side note, regarding “additional network hop for now”, if your gateway and monolith (or federated) services are deployed in the same cluster (assuming K8s setup), this network hop latency should not be of concern. You can use query tracing to find more details about the query resolution timing.

1 Like

Here’s how we’re doing it:

  • we have an existing monolith service (REST)
  • We’ll create an accounts service which will have federation enabled
  • In a feature flag, we’ll migrate to account service which is inside a federated gateway
  • Slowly we add more services inside our one graph.
  • At any point during the rollout, if something goes wrong, we turn off the feature flag
  • At the end of everything we should have all requests coming to gateway and no request going to REST API
  • At which point we’ll archive the github repository and remove deployments related to that project.

I don’t know if that’s something you can try, but I think it’s very safe given you’re using feature flags and you have rollback strategy.