Skip to content
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

Modular types and incremental imports #340

Closed
mdebbar opened this issue May 29, 2017 · 7 comments
Closed

Modular types and incremental imports #340

mdebbar opened this issue May 29, 2017 · 7 comments

Comments

@mdebbar
Copy link

mdebbar commented May 29, 2017

Follow up on: https://twitter.com/mdebbar/status/869249679862546432
I'll try to illustrate the example from Twitter with more details.

Let's say we have a simple schema for only posts and comments. The QueryType has one field getPost. And the PostType has a field comments.

When using graphql-js, the top-level schema file doesn't have to import everything. It only imports the types necessary for the top-level query fields, and everything else will be included through incremental imports:

// schema.js
import { GraphQLSchema, GraphQLObjectType } from 'graphql';
import PostType from './PostType.js';

const QueryType = new GraphQLObjectType({
  name: 'Query',
  fields: {
    getPost: {
      type: PostType,
      args: { id: ... },
      resolve: (root, { id }) => getPostFromDB(id),
    },
  },
});

export default new GraphQLSchema({
  query: QueryType,
});
// PostType.js
import { GraphQLObjectType, GraphQLList, GraphQLInt } from 'graphql';
import CommentType from './CommentType'

export default new GraphQLObjectType({
  name: 'Post',
  fields: {
    id: { type: GraphQLInt },
    comments: {
      type: new GraphQLList(CommentType),
      resolve: (post) => post.getCommentsFromDB(),
    },
  },
});

I like the approach of graphql-tools which looks cleaner and less verbose, but I couldn't find a way to achieve a structure similar to the above.

cc @stubailo

@stubailo
Copy link
Contributor

Hmm, right now you would have to do:

// PostType.js
import Comment from './CommentType';
import { merge } from 'lodash';

export default {
  typeDefs: [`
    type Post {
      id: Int
      comments: [Comment]
    }
  `, ...Comment.typeDefs],

  resolvers: merge({
    Post: {
      comments: (post) => post.getCommentsFromDB()
    }
  }, Comment.resolvers)
};
import { makeExecutableSchema } from 'graphql-tools';
import { merge, uniq } from 'lodash';
import PostType from './PostType.js';

const typeDefs = [`
  type Query {
    getPost(id: Int!): Post
  }
`, ...PostType.typeDefs];

const resolvers = merge({
  Query: {
    getPost: (root, { id }) => getPostFromDB(id),
  }
}, PostType.resolvers);

export default makeExecutableSchema({
  typeDefs: uniq(typeDefs),  // Need the uniq to avoid having the same string twice
  resolvers
});

I can see where you're coming from that it could be easier. I think something which makes it more natural to pass around a schema/resolver pair and merge them together would be a good fit inside this package, and would probably be just a few lines of code!

Would love to talk about a design for that.

@stubailo
Copy link
Contributor

One point here is that I think I just have a bit of a different mental model - in my mind I feel like all of the types to be kind of part of a whole that are all merged together, rather than small modules with interdependencies.

But we should support both ways of doing stuff, it's just a matter of having a nice unit to pass around/import.

@mdebbar
Copy link
Author

mdebbar commented Jun 3, 2017

Right. I agree with your point about the different mental models.

I think of types as an interconnected graph. And to define a schema, all we need to do is point to the Query node of that graph, and let everything else be figured out automatically:

                            Like *-------------|
                             *                 |
                             |                 |
                             *                 |
Schema * ---- * Query *---* Post *---* Comment |
                  *          *           *     |
                  |          |           |     |
                  |          *           |     |
                  |-------* User *-------|     |
                              *                |
                              |----------------|

So yeah, each type in my mind is a standalone node in the graph.

@stubailo
Copy link
Contributor

stubailo commented Jun 4, 2017

Sweet diagram! But yes I'm definitely into having a nicer API for that model.

@mdebbar
Copy link
Author

mdebbar commented Jun 11, 2017

@stubailo I'm trying to come up with a pattern for exporting types as a unit. One thing that I couldn't figure out is how to do the equivalent ofisTypeOf for unions and interfaces.

@stubailo
Copy link
Contributor

Any progress on this? Seems like still a great idea!

@stubailo
Copy link
Contributor

I think we should address this as part of a way to make things more modular/incremental, and I'm planning to use #185 as the main issue for that topic. Closing this but that doesn't mean it's not important!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants