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 GraphQL Docs) but we are not sure if we can have production traffic with an Apollo gateway serving traffic to both instances.
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 in Apollo Federation - Apollo GraphQL Docs
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.
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 differentendpoint 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.
@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.
@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.
@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 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.
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
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.
@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 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.
Here is an example of the types of schemas we would want to support.
This first one represents a legacy monolith that we are replacing with federation. We want to keep it intact as a monolith so we can roll back to it, split traffic to it when deploying the new service(s), etc. We would prefer to make minimal, if any changes to it:
type Query {
commonFunction(foo: Int!): Boolean
aThing: Thing
anotherThing: AnotherThing
}
type Thing {
name: String!
}
type AnotherThing {
name: String!
}
The next one represents our first subgraph, which we want to run in federation with the legacy service:
extend type Query {
commonFunction(foo: Int!): Boolean
aThing: Thing
}
extend type Thing {
name: String!
}
Later services will be developed to replace the rest, and the monolith will be retired.
When running rover supergraph compose --config ./federate.yml, we get:
error[E029]: Encountered 3 build errors while trying to build a supergraph.
Caused by:
Encountered 3 build errors while trying to build the supergraph.
UNKNOWN: Field "Query.commonFunction" can only be defined once.
UNKNOWN: Field "Query.aThing" can only be defined once.
UNKNOWN: [subgraph1] Thing.name -> Field "Thing.name" already exists in the schema. It cannot also be defined in this type extension. If this is meant to be an external field, add the `@external` directive.
The subgraph schemas you provided are incompatible with each other. See https://www.apollographql.com/docs/federation/errors/ for more information on resolving build errors.
We have tried sprinkling @external around, but that makes thing worse, actually.
In Fed 1, it’s not possible for two graphs to provide the same field — that the error you’re running up against. I tried to illustrate the full field migration workflow in my GraphQL Summit talk last year: Change Management with Apollo Federation - Promo - YouTube … please let me know if I can elaborate on this!
Actually, the above works–I had just generated supergraph.graphql incorrectly. Once I fixed that, I was able to issue a basic query.
What is the migration path for subscriptions in the monolithic server? We have type Subscription declared in the monolithic schema, but when I run rover supergraph compose --config ./supergraph-config.yaml > ./data/supergraph.graphql, I get the following error:
error[E029]: Encountered 1 build error while trying to build a supergraph.
Caused by:
Encountered 1 build error while trying to build the supergraph.
UNKNOWN: [whatever] Subscription -> `Subscription` is an extension type, but `Subscription` is not defined in any service
The subgraph schemas you provided are incompatible with each other. See https://www.apollographql.com/docs/federation/errors/ for more information on resolving build errors.