This is a continuation of my comments on #116.
To answer @stubailo's question:
With graphql-utilities the idea is very simple, GraphQL.js provides a JavaScript implementation to define a GraphQL schema but we could always use the less verbose schema language. The initial goal of the library was to allow anybody to build anything that could be built with GraphQL.js but using the schema language.
For example,
to build a schema:
const { __schema } = build(`
schema {
query: Query
}
`, [Query]); // Query is a GraphQLType whose name is `Query`
to build a type:
const { Query } = build(`
type Query {
status: Boolean!
}
`, {
status: () => true, // here we use a shortcut for the resolver of the `status` field.
});
here's another type:
const { Weekday } = build(`
enum Weekday {
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
}
`);
A few things to note:
build, it would simply be exported with its name in the returned type map. When building a single type, you could return that type instead of a type map but I've found this to result in a more confusing API (the library currently does that but I was planning to remove support for it).__schema name above is a simple selection, it could be any other name but it was the one that made the most sense after much thought.graphql-tag for syntax highlighting and other nice perks. Implementing this would be extremely simple.resolver field, you simply pass in the resolver. Here's the difference with and without:with shortcut:
const { Query } = build(`
type Query {
status: Boolean!
}
`, {
status: () => true,
});
without shortcut:
const { Query } = build(`
type Query {
status: Boolean!
}
`, {
status: {
resolver: () => true,
// here you can add descriptions or deprecation reasons.
},
});
buildASTSchema) but this type of magic makes the API a bit confusing. It could be kept or removed but what I know for sure is that good error messages are essential for debugging these things.build takes the following parameters:There are more things I have in mind for this library (like custom types for URLs, Email, etc.) but I feel like starting with build is a good start. What graphql-tools currently does with appplying resolvers by modifying the schema after the fact feels hacky, and doesn't lend itself for colocation of resolvers and definitions which is why ultimately I built graphql-utilities.
If my approach is something of interest I would love to discuss it more and potentially even make it a part of graphql-tools as I'm honestly just looking to benefit the ecosystem as a whole and not have another library to compete (https://xkcd.com/927/ heh).
Thanks for all the great work you guys have been doing with the Apollo stack. Truly amazing stuff! 馃槃
I like that approach, and I think it's complementary to graphql-tools. GraphQL-tools has the advantage that the schema becomes much easier to read, while graphql-utilities has the advantage of keeping the resolver code close to the schema types that it applies to.
@helfer,
You can always separate the resolvers like you do in graphql-tools and then call build(declaration, resolvers, typeDependencies) with all your declarations and resolvers.
Colocating the resolvers is an advantage but it's not 100% required if you don't want to do it that way.
EDIT: You could build the entire schema just like in graphql-tools and simply concatenate all the strings and pass the entire schema declaration into build.
@migueloller are you willing to create a PR adding this feature? :)
@DxCx, definitely! Could you take a look at https://github.com/bloveit/graphql-utilities/pull/12
There I go over some of the work I want to do to get the build API in a stable place. After you go over that I'd love to discuss what would be the best way this could be integrated with graphql-tools. If this API is implemented the API for graphql-tools would change a little bit (instead of the typeDefinitions argument being an array of strings it would be an array of GraphQL.js types).
I'm in the Apollo Slack as @miguel if you want to have a conversation there! Would be more than happy to chat about the motivation behind the build API.
hi @migueloller,
sorry it took me a while to check this =)
anyway, yeah, this is more or less what i had in mind,
the ability to transform typeDef + resolver into a map,
so the user can use this API in two different apis,
it can be either passed to makeExecutableSchema along with the others,
(I think we might want another key in the options for those, like prebuilt or something, else they should go to resolvers)
or buildGraphqlType (or any other name) to make it a graphql object.
that should give people the ability to compose their GQL into modules.
also, we need to think how to specify context requirements for a type..
for example, type X expects context to have getX function.
@DxCx,
Awesome! I'm currently working on bloveit/graphql-utilities#12 as fast as I can so I'll let you know as soon as that's done.
With regards to context requirements, do we really want to limit how context gets defined by the library consumer? Shouldn't they simply provide a root value that takes advantage of the default resolver?
oh no, i don't want to limit anything,
i'm just saying we need to think how to document it so it can be shipped with the built "module" that's all ;)
Hey I'm going through and looking at some of the issues here, and this is still something that comes up a lot! We're going to try to address some of these in the coming weeks :)
Going to use this as the main issue for this idea.
@stubailo, sounds good!
Please let me know if you want any help/contributions.
Any update on this issue?
I'm looking for a temporary solution to obtain such a functionality, is there a ny way?
@stubailo did you have any progress on this?
Folding into #1306.
@yaacovCR I took a look at #1306 but didn't quite understand how (or whether) this issue was resolved. As of v6, is it possible to build a schema from parts where some of them use SDL and some of them plain graphql-js?
This is possible using stitchSchemas using types property?
but that is not really new functionality, it was just given a new property name but it used to work just fine in the schemas property before that was broken out into subschemas...
Aha, I might be confused here, thought it's an issue about mergeTypeDefs / @graphql-tools/merge. We don't use schema stitching, just merging. Do you know if that works? All examples show SDL and I wasn't able to find much info about plain graphql-js support.
Not as familiar with the merge package. @ardatan ?
Note that you don't actually have to use stitching here, If you don't pass any sub schemas you can just merge types and typedefs using the stitching function but there is no delegation
Then you would get a schema output, what kind of output are you looking for
@borekb mergeTypeDefs accepts an array of the following types: string | Source | DocumentNode | GraphQLSchema.
The function works by merging types represented as AST nodes, which is what you get when you use graphql-tag or call parse on a string containing SDL. If the function receives a string, Source or GraphQLSchema, it can convert those inputs back into an AST object and merge them that way.
The function doesn't support passing in instances of GraphQLObjectType or the other type classes directly. However, if those types are part of a schema, you can just pass in the schema. If they are not part of any schema, you can still pass them in this way:
const schema = new GraphQLSchema({
types: [FooType, BarType],
});
const document = mergeTypeDefs([schema]);