Currently ApolloGateway supports the serviceList option for remote GraphQL services and localServiceList for local GraphQL schemas, but they cannot be used together. It would be great if ApolloGateway allowed both remote and local schemas.
@tjwallace this is currently possible today (though lacking in documentation as we plan on making this more "native" in the next major version of Apollo Server). This can be done by returning a LocalGraphQLDataSource instead of a remote one when using buildService
Sorry I should have mentioned that I had tried returning a LocalGraphQLDataSource inside of buildService but ran into some issues:
url in the service definition.buildService (a second time for the service), but does not include anything originally in the definition (like schema) so I have to do a check on name and then reference schema from a higher scope. Is this expected? I didn't originally notice this so now I have it working.Here is what I have now for reference. Is this the "correct" way to use LocalGraphQLDataSource?
// local schema
const schema = buildFederatedSchema([Foo, Bar, Baz]);
const serviceList = [
// can't add `schema` to this object because `buildService()` will eventually be
// called a second time without it (only name, url and typeDefs)
{ name: 'local', url: 'local' },
{ name: 'remote', url: 'http://remote.com/graphql' }
];
const gateway = new ApolloGateway({
serviceList,
buildService({ name, url }) {
if (name === 'local') {
return new LocalGraphQLDataSource(schema);
}
return new RemoteGraphQLDataSource({ url });
}
});
But buildFederatedSchema() would fail on User.id if one schema references the other. So I don't see how using LocalGraphQLDataSource would work.
GraphQLSchemaValidationError: Field "User.id" can only be defined once
``
const server = new ApolloServer({
schema: buildFederatedSchema([{
typeDefs: gql
extend type Query {
me: User
}
type User @key(fields: "id") {
id: ID!
username: String!
}
`,
resolvers: [],
}, {
typeDefs: gql`
extend type Query {
topProducts(first: Int = 5): [Product]
}
type Product @key(fields: "upc") {
upc: String!
name: String!
price: Int
}
`,
resolvers: [],
}, {
typeDefs: gql`
type Review {
body: String
author: User @provides(fields: "username")
product: Product
}
extend type User @key(fields: "id") {
id: ID! @external
reviews: [Review]
}
extend type Product @key(fields: "upc") {
upc: String! @external
reviews: [Review]
}
`,
resolvers: [],
}]),
context: ({ req }) => ({ user: req.user }),
})```
Where does this stand ? is it possible to do or not? Just wanted to be clear.
@5amfung Seems like buildFederatedSchema still just concatenates, and you should be splitting them into local services for each module instead of just an array of modules into buildFederatedSchema.
With help of graphql-transform-federation I'm going to try connect to a gateway not federated service
So at the very end it will be something like:
Wondering if instead of having dedicated proxy running for each service I can put it inside gateway itself, e.g.:
Considerations here are following:
From a conversation above I did not understand whether this feature is implemented or not or is it in roadmap, at moment I do see that GatewayConfig is a union of RemoteGatewayConfig and LocalGatewayConfig so it should be possible to pass both servicesList and localServiceList as a consturctor options but from the gateway code it seems that it is expecting typeDefs and wont receive ready to use schema
After having a closer look at @tjwallace answer I also were able to setup this by just adding ternary into buildService which now returns LocalGraphQLDataSource(federatedSchem) or RemoteGraphQLDataSource based on config
@mac2000 :- how will the queries execute for schemas which you have passed into constructor of LocalGraphQLDataSource, since basically you have mocked the schemas?
@rahul22048 oh it is very old at very end we did make following:
right inside apollo federation gateway wrap all services with code pieces from graphql federation transformation
in at very end our gateway was something like:
var gateway = new Gateway({ services: process([
{name: 'federated-service-1', url: 'http://localhost:3000'},
{name: 'nonfederated-service-2', url: 'http://localhost:5000', config: require('./nonfederated-service-2.js')},
]) })
where process function inside returned records as is if there were no config property, other wise do transformation with applied configs
and it was working for a while, but later we did manage how to make federation support in dotnet so no need for this, at moment everything is working without any proxies
Most helpful comment
Sorry I should have mentioned that I had tried returning a
LocalGraphQLDataSourceinside ofbuildServicebut ran into some issues:urlin the service definition.buildService(a second time for the service), but does not include anything originally in the definition (likeschema) so I have to do a check onnameand then referenceschemafrom a higher scope. Is this expected? I didn't originally notice this so now I have it working.Here is what I have now for reference. Is this the "correct" way to use
LocalGraphQLDataSource?