Combine federated and not federated services into one
Closed this issue · 13 comments
Suppose we have something like:
articles.js localhost:4002 federated
const { ApolloServer, gql } = require("apollo-server");
const { buildFederatedSchema } = require("@apollo/federation");
const articles = [
{
id: "1",
title: "article1",
body: "article1 body"
},
{
id: "2",
title: "article2",
body: "article2 body"
},
{
id: "3",
title: "article3",
body: "article3 body"
}
];
const typeDefs = gql`
type Query {
articles: [Article]!
article(id: ID!): Article
}
type Article @key(fields: "id") {
id: ID!
title: String
body: String
}
`;
const resolvers = {
Query: {
articles: () => articles,
article: (_, { id }) => articles.find(({ id: articleId }) => id === articleId)
}
};
const server = new ApolloServer({
schema: buildFederatedSchema([
{
typeDefs,
resolvers
}
])
});
server.listen({ port: 4002 }).then(({ url }) => console.log("articles:", url));accounts.js http://localhost:4001 not federated
const { ApolloServer, gql } = require("apollo-server");
const accounts = [
{
id: "1",
name: "Alex",
username: "@mac"
},
{
id: "2",
name: "Yar",
username: "@yar"
}
];
const typeDefs = gql`
type Query {
accounts: [Account]!
account(id: ID!): Account
}
type Account {
id: ID!
name: String
username: String
}
`;
const resolvers = {
Query: {
accounts: () => accounts,
account: (_, { id }) => accounts.find(({ id: accountId }) => id === accountId)
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen({ port: 4001 }).then(({ url }) => console.log("accounts:", url));.meshrc.yaml
sources:
- name: Accounts
handler:
graphql:
endpoint: http://localhost:4001/graphql
transforms:
- federation:
types:
- name: Query
config:
extend: true
- name: Account
config:
keyFields:
- id
- name: Articles
handler:
graphql:
endpoint: http://localhost:4002/graphqlExpected results: Schema should have _Entity union with both Account and Article
Actual results: union not being merged
The same is true for other federation features, like _Services etc
First, you are using federation transform for a schema that is already federated. If you want to consume a federated schema in GraphQL Mesh, use federation handler not graphql handler; https://graphql-mesh.com/docs/handlers/federation
Federation transform is to convert non-federated schemas to federated ones.
perhaps, relevant here too: federating the services via graphql-transform-federation may require adding a resolveReference resolver (?). Is there a way to do so from the mesh config?
You can use additionalResolvers to add reference resolver as in Apollo Federation specs. Sorry for the lack of documentation related to Federation in Mesh. But we're working on a detailed recipe :)
@ardatan thank you for your point I'm not really sure if I get it right
first miss understanding - you are saying that I'm using federation transformation for already federated service which is not true (take a closer look, I'm using federation transformation on Accounts service which is not federated)
second is about usage of federation handler not graphql handler, even if i will change yaml to this one:
sources:
- name: Gateway
handler:
federation:
serviceList:
- name: Articles
url: http://localhost:4002/graphql
- name: Accounts
handler:
graphql:
endpoint: http://localhost:4001/graphql
transforms:
- federation:
types:
- name: Query
config:
extend: true
- name: Account
config:
keyFields:
- idThere still will be only Account in entities union unfortunately
@mac2000 By the way you are right I misunderstood. So right now, I am not sure if Mesh currently supports this kind of use case. I will test and give an update soon.
Did setup micro repository - https://github.com/mac2000/graphql-mesh-issue-296
e.g.:
git clone https://github.com/mac2000/graphql-mesh-issue-296
cd graphql-mesh-issue-296
npm i
node accounts.js
node articles.js
npm start
open http://localhost:4000
hope it will be much easier to understand what i'm talking about
Just to clarify, when we are hiding our federated service by gateway it does remove all federation related directives, types, ets and then when mesh combines everything together there will be nothing left
And one more, I'm not sure but why federation specific stuff is still in output at all after mesh, where should _entities resolvers go?
PS: @d-led yep, you going to go thru 7 rounds of hell, my personal recommendation is to start with underlying library and wire up everything with it just to figure out how it all works together and only then come back to mesh, otherwise it will be way to paint full
sources:
- name: Accounts
handler:
graphql:
endpoint: http://localhost:4001/graphql
transforms:
- federation:
types:
- name: Query
config:
extend: true
- name: Account
config:
keyFields:
- id
- name: Articles
handler:
graphql:
endpoint: http://localhost:4002/graphqlSo federation handler removes that union and that means you need to use graphql handler not federation one, could you try the configuration above with the canary version in this PR?
This PR fixes the union merging issue #297
I saw your last comment. Currently it is not possible with a single Mesh configuration but you can create this architecture with multiple mesh configurations(that will be almost same with the first graph).
So I'll keep this issue open (as a feature request) because I think we can implement a solution for your use case.
You can use
additionalResolversto add reference resolver as in Apollo Federation specs. Sorry for the lack of documentation related to Federation in Mesh. But we're working on a detailed recipe :)
@ardatan: for now, I just extended the type directly, it's at least readable. It would be interesting to see how additionalResolvers could look like.
Currently we're improving Federation on Mesh;
PR; #367
Example; https://github.com/Urigo/graphql-mesh/tree/federation-merger/examples/federation-example
Alpha version; https://github.com/Urigo/graphql-mesh/pull/367
Could you try and let us know if it works?
Available in v0.1.17