You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于express-graphql、Mongoose拆分大型GraphQL Schema文件

Great question! When your GraphQL schema starts getting unwieldy, splitting it into modular, single-responsibility files makes your code way easier to maintain and scale. Here’s a straightforward approach that fits your current setup (using express-graphql, Mongoose, no buildSchema or Apollo):

Step 1: Set up a modular directory structure

First, reorganize your GraphQL-related code into a dedicated folder with subdirectories for different components:

your-project/
  models/
    book.js
    author.js
  graphql/
    types/          # For your object types (BookType, AuthorType)
      BookType.js
      AuthorType.js
    queries/        # For root queries
      RootQuery.js
    mutations/      # For mutation definitions
      Mutations.js
    schema.js       # Main schema entry point
  app.js

Step 2: Split your Object Types

Break out each GraphQLObjectType into its own file in the types/ directory. We handle circular references (Book ↔ Author) by requiring the dependent type inside the fields function (since it’s executed lazily):

graphql/types/BookType.js

const graphql = require('graphql');
const Book = require('../../models/book');
const { GraphQLObjectType, GraphQLID, GraphQLString } = graphql;

const BookType = new GraphQLObjectType({
  name: 'Book',
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    genre: { type: GraphQLString },
    author: {
      type: require('./AuthorType').AuthorType,
      resolve(parent, args) {
        return Book.findById(parent.authorID);
      }
    }
  })
});

module.exports = { BookType };

graphql/types/AuthorType.js

const graphql = require('graphql');
const Author = require('../../models/author');
const { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLInt, GraphQLList } = graphql;

const AuthorType = new GraphQLObjectType({
  name: 'Author',
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    books: {
      type: new GraphQLList(require('./BookType').BookType),
      resolve(parent, args) {
        return Author.find({ authorID: parent.id });
      }
    }
  })
});

module.exports = { AuthorType };

Step 3: Extract Root Queries

Move your root query definitions into their own file:

graphql/queries/RootQuery.js

const graphql = require('graphql');
const Book = require('../../models/book');
const Author = require('../../models/author');
const { GraphQLObjectType, GraphQLID, GraphQLList } = graphql;
const { BookType } = require('../types/BookType');
const { AuthorType } = require('../types/AuthorType');

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {
    book: {
      type: BookType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Book.findById(args.id);
      }
    },
    author: {
      type: AuthorType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return Author.findById(args.id);
      }
    },
    books: {
      type: new GraphQLList(BookType),
      resolve(parent, args) {
        return Book.find({});
      }
    },
    authors: {
      type: new GraphQLList(AuthorType),
      resolve(parent, args) {
        return Author.find({});
      }
    }
  }
});

module.exports = { RootQuery };

Step 4: Extract Mutations

Do the same for your mutation definitions:

graphql/mutations/Mutations.js

const graphql = require('graphql');
const Book = require('../../models/book');
const Author = require('../../models/author');
const { GraphQLObjectType, GraphQLString, GraphQLID, GraphQLInt, GraphQLNonNull } = graphql;
const { BookType } = require('../types/BookType');
const { AuthorType } = require('../types/AuthorType');

const Mutation = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    addAuthor: {
      type: AuthorType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        age: { type: new GraphQLNonNull(GraphQLInt) }
      },
      resolve(parent, args) {
        let author = new Author({ name: args.name, age: args.age });
        return author.save();
      }
    },
    addBook: {
      type: BookType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        genre: { type: new GraphQLNonNull(GraphQLString) },
        authorID: { type: new GraphQLNonNull(GraphQLID) }
      },
      resolve(parent, args) {
        let book = new Book({ name: args.name, genre: args.genre, authorID: args.authorID });
        return book.save();
      }
    }
  }
});

module.exports = { Mutation };

Step 5: Assemble the Main Schema

Update your root schema.js to import and combine all the modular components:

graphql/schema.js

const graphql = require('graphql');
const { GraphQLSchema } = graphql;
const { RootQuery } = require('./queries/RootQuery');
const { Mutation } = require('./mutations/Mutations');

module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation
});

Step 6: Update app.js (if needed)

If your schema path changed, just adjust the require statement—otherwise, your existing code works exactly as before:

const schema = require('./graphql/schema'); // Verify the path matches your new structure
app.use('/api', graphqlHTTP(async req => ({ schema, graphiql: { headerEditorEnabled: true } })));

Key Notes

  • Circular Reference Handling: By requiring dependent types inside the fields function (which runs lazily), we avoid the "undefined" errors that come with mutual references between Book and Author types.
  • Maintainability: Each file now focuses on one specific part of your schema—you can update Book fields, add a new mutation, or tweak a resolver without digging through a massive single file.
  • Scalability: Adding new types (like Publisher) or features later just means adding new files to the appropriate directories, rather than cluttering your main schema.

内容的提问来源于stack exchange,提问作者mitchldtn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:51:43