首页 > 解决方案 > 如何将大的graphql模式文件分成多个小文件?

问题描述

我正在使用 graphql、express-graphql 和猫鼬。我没有使用 buildSchema。下面是我用来学习 graphql 的代码,我现在对使用 apollo-server 不感兴趣。问题是我的模式文件现在变得相当大,我希望让事情变得更好。

我如何将此代码分解为多个文件?

架构.js:

const graphql = require('graphql');
const Book = require('../models/book');
const Author = require('../models/author');

const { 
    GraphQLObjectType, 
    GraphQLSchema, 
    GraphQLString, 
    GraphQLID,
    GraphQLInt,
    GraphQLList,
    GraphQLNonNull
 } = graphql;

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

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

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({});
            }
        }
    }
});

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 = new GraphQLSchema({
    query: RootQuery,
    mutation: Mutation
});

我如何在 app.js 中调用架构:

app.use('/api', graphqlHTTP( async req => ({
    schema,
    graphiql: { headerEditorEnabled: true }
})));

标签: graphql

解决方案


这都可以归结为经典的 JS 导入和导出。您在这里所做的一切都可以在单独的文件中定义和导出,并相应地导入您需要的地方。我不完全确定我会鼓励以这种方式思考您的架构,但要回答您的问题:

您可以创建以下文件夹结构:

typedefs/bookType.js
typedefs/authorType.js
typedefs/query.js
typedefs/mutation.js

这允许您将架构类型定义组织为更小的、单独的、可导出的单元。

例如,您的 bookType.js 文件可能如下所示:

// Declare your imports at the top
import { AuthorType } from './authorType';
import Author from '../models/author';

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

您的作者类型可能如下所示:

import { BookType } from './bookType';
import Book from '../models/Book';
...

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

需要注意的几点:

  1. 注意循环依赖。BookType 将需要导入 AuthorType,而 AuthorType 将需要导入 BookType。循环依赖可能导致难以处理的错误,此外还可能导致堆/内存问题并破坏类型检查器(如 Typescript 或 FlowType)。

  2. 如果您采用这种方法,您的架构将变得更难推理。与 DB 模型不同,在 DB 模型中,每个模型/表都是其自己的独立实体,几乎没有(如果有的话)依赖关系,当您的 GraphQL 模式可以轻松表达类型之间的数据相互依赖关系时,它真的会蓬勃发展。这就是为什么,鉴于个人经验尝试了几次,我不会鼓励这种方式来编写你的模式。请参阅我在此处详细说明此问题的另一篇文章:https ://stackoverflow.com/a/65035430/4301222


推荐阅读