-
Notifications
You must be signed in to change notification settings - Fork 2k
Merging schemas #223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Just have each project export its types and combine those types together On Sun, Nov 8, 2015 at 3:43 PM Kristijan Sedlak [email protected]
|
@KyleAMathews Thanks, that's what we plan to do. I just want to make sure that our thinking is correct. |
We maintain one schema at Facebook. Different teams are responsible for maintaining the types that are specific to their products, but there is only one final schema that combines all the types together into one GraphQL service available to our client applications. |
@leebyron Thanks! |
@leebyron How is this done when using schema lang? If I run |
You're correct. If you're using the schema language to build a schema than you need to first combine it into a single string before calling buildSchema. That typically is a nice developer experience for small to medium sized schema, though for more complex schema we recommend building the schema programmatically. Even in this case you still need to collect all the types to assemble the schema. A similar operation to collecting all the strings before calling buildSchema |
Hmm, it seems that I don't strictly need to combine it to a string but a list of strings. There seems to be an util for combining schemas however, |
For anyone else looking for a way to merge You can use this to merge # schema1.graphql
type Query {
foo: String
}
type Mutation {
bar(input: String): String
} # schema2.graphql
type Query {
hello: String
}
type Mutation {
world(input: String): String
} and you ran this: npm install -g gql-cli
gql merge **/*.graphql You'd end up with this output: type Query {
foo: String
hello: String
}
type Mutation {
world(input: String): String
bar(input: String): String
} It should work with other type definitions too (enums, interfaces, inputs, etc). |
@liamcurry wow, this would be a really awesome addition to Is it available as a library without the CLI? |
@stubailo Yes it is. Check out the The source for that is all in this file: https://github.com/liamcurry/gql/blob/master/packages/gql-merge/src/index.js Here's an example (untested): import {mergeStrings} from 'gql-merge'
const testSchema1 =
`type Query {
hello: String
}`
const testSchema2 =
`type Query {
world: String
}`
const resultSchema = mergeStrings([testSchema1, testSchema2])
console.log(resultSchema)
/* Should print this to the console:
type Query {
hello: String
world: String
}
*/ |
Nice, we should definitely use that in |
I having issues where two merged schemas have a name-space collision. Say "Reservation" is defined in both schemas and when I try to merge them into a Root_Schema it is throwing an error. Are there any best practices that I should follow to avoid such problems? |
Hard to say without knowing why you're merging schema in the first place. If you're merging two schema that come from two unrelated sources (perhaps two different companies) - then you're treading into fairly new GraphQL territory! I've seen people attempting this sort of thing work around this by adding a pseudo namespace to the foreign source. For example if you were merging Github's GraphQL schema into yours, you might replace every type in Github's schema with If you're merging two schema that you control, then you likely need some sort of internal tool or integration test which blocks commits which introduce these kinds of issues. While we don't merge schemas anywhere at Facebook, we have a similar situation where someone might inadvertently create a new type which is named the same as an existing type in our schema, resulting in two types of the same name. We run a simple integration test before commit which asserts that this doesn't occur. |
I know what I am about to write goes against the single root node concept of GraphQL. But to me, this could be another case of splitting the root to a bunch of uniquely identifiable resources. With this split there is no need to mix schema at all. This would only have the requirement of each resource needing its own unique name. So, for the reservations example mentioned, you'd need to have "/reservationsA" and "/reservationsB". Sure, it means extra calls to the server to get the data, but it isn't going to REST kinds of extremes. So, is calling on the "main branches" of the graph really all that bad? With a big app, this "one level down from the root" would offer a slight avoidance of too much coupling, which obviously a singular schema is causing (like with this issue and others). I'd love to understand why this is a stupid idea. I'm sure there is a reason for wanting to always have just the one "graph" and not request only the main branches and only when they are needed. Scott |
One use case is just project file organization. This proposal is intuitive to me: ardatan/graphql-tools#186 Spreading out query/type/mutation definitions across a directory structure organized by entities.
Without some pattern for dividing things up, how do you avoid enormous Query definitions at Facebook? Consider this file defining a single entity's query: https://github.com/joefraley/humane-society-api/blob/master/api/animals/queries.js It already seems long for my taste. I can only imagine that things are more complicated at Facebook. |
@liamcurry |
@smolinari namespace collision when naively merging means you are have distinct two Bounded Contexts. The recommendation from Domain Driven Design would be to either have two graphql resources/domains (ie two completely seperate graphs) with shared references or produce a new Bounded Context for your UI domain that is designed specifically to support you UI domain.[1] Why is this necessary? The longer story is about impedance mismatch between your layers,[2] but, in short, if you @akeelnazir beyond this I've been putting together [1] I use UI domain here since graphql's main aim is to support more efficient communications between UI code and server code. |
@jamesgorman2 - right. I was thinking the whole time the reservationA and reservationB example is a poor one for splitting up the graph branches into their own resources/ APIs. There should only be a single "reservation" resource. @leebyron Lee said,
And I was contemplating some about that. How do teams know they aren't duplicating types? If the merge tool mentioned above works, that is great and there are no worries. But, doesn't duplicating types unknowingly mean wasted developer effort, at least theoretically? Does this possible duplication happen so rarely, it doesn't matter? Or maybe, to avoid duplication, the front-end devs are told to first search the Schema with a tool like GraphiQL to see what is available first, before requesting that any new Types be added? I'd really love to learn the Facebook workflow dealing with Type creation better. It would help me, and I am certain others too, understand possible best practices, when working with a large schema. A couple questions that burn in my mind are: How often does the Facebook schema get updated/ changed? Scott |
A GraphQL schema can't have more than one definition of the same type. Facebook runs an integration test to prevent this: graphql#223 (comment) With this PR the `buildASTSchema` step throws, causing any tests that load the schema to fail.
Maybe I'm missing something, but is #744 a viable solution to preventing duplicate type definitions? |
Hey there! Sorry to comment on a closed issue, but I'm currently trying to merge schemas and going with the namespace approach @leebyron mentioned above. Does anyone have a straight forward approach to this? Currently I'm trying to muck around with the schema ast using visit and hit success renaming types until I hit the ofType key, which has its own nested structure. Is there a better way to merge the schemas? What id like to do is just namespace all types in a schema with some prefix. The end goal being is showing the types from many GraphQL servers in one GraphiQL. I'm trying to build a GraphQL proxy server! |
I recommend looking at extendSchema.js in this repo. You can likely borrow a lot from how it is implemented for this purpose |
Hey @abhiaiyer91 Take a look at the merge-graphql-schemas package. Maybe your use case is a little different from what the package is trying to solve, but we could make some adjustments if it's something that might benefit other people as well. 😄 Cheers! |
@abhiaiyer91 I also have the need to setup a proxy server. We have ~10 different systems with nearly identical schemas (but potential to be different) and another system with a completely different schema. We want to be able to query data from a single endpoint and have that server handle passing the request to the appropriate other GraphQL server for resolving. I'd be curious to see what you come up with. |
Oh man! I have a dope solution to this problem I'll open source with a few more prod level tests! Free to use!! |
@abhiaiyer91 Can't wait to see it! |
@abhiaiyer91 I am curious to see the solution you developed to this problem. |
@jrop I worked with the apollo team to get this done! https://github.com/Workpop/roxy is sort of an outdated version of this but the source code lives in |
@abhiaiyer91 Where is it in |
This post demonstrates how to modularize your graphql schemas. Hope it helps! :) |
I work on a huge project. To ensue project's long-term maintainability we decided to split the application into 3 standalone pieces thus we now have 3 specialized teams. Each app exposes its own GraphQL schema. At the end we plan to create the 4th app which will merge all 3 pieces together into a
gateway
application using theexpress-graphql
package.What is the best way to merge schemas? What we would need is a mechanism similar to Express Router. Our current plan is to make all 3 apps available as private packages from which we can build a new schema for the main (4th) app. Well, we could make each app act as a standalone private graphql server and then the main application would just send requests to sub-apps but I believe it could potentially represent a huge overhead. Am I wrong?
Are there any plans for supporting this? What do you suggest? How do you handle this at Facebook?
The text was updated successfully, but these errors were encountered: