【问题标题】:How to split type definitions and resolvers into separate files in Apollo Server如何在 Apollo Server 中将类型定义和解析器拆分为单独的文件
【发布时间】:2020-06-30 00:28:28
【问题描述】:

index.ts:

  const server = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req, res }: any) => ({ req, res })
  });

UserSchema.ts

export const typeDefs = gql`
  scalar TimeStamp
  type Query {
    getUser(id: Int!): User
  }
  type Mutation {
    addUser(
      name: String!
      email: String
      age: Int
      register_at: TimeStamp!
    ): Boolean!
  }
  type User {
    id: Int!
    name: String!
    email: String!
    age: Int!
    register_at: TimeStamp!
  }
`;

UserResolver.ts

export const resolvers = {
  TimeStamp: timeStamp,
  Query: {
    getUser: async (_: any, args: any) => {
      const { id } = args;

      return await User.findOne({ where: { id: id } });
    }
  },
  Mutation: {
    addUser: async (_: any, args: any) => {
      const { name, email, age, register_at } = args;
      try {
        const user = User.create({
          name,
          email,
          age,
          register_at
        });

        await user.save();

        return true;
      } catch (error) {
        return false;
      }
    }
  }
};

如果我有额外的类型定义和解析器,例如BookSchema.tsBookResolver.ts,我想知道如何初始化我的 Apollo Server 实例。

【问题讨论】:

    标签: typescript graphql graphql-js apollo-server


    【解决方案1】:

    类型定义

    ApolloServer 构造函数可以接受一个数组,而不仅仅是一个 DocumentNode 对象。所以你可以这样做:

    const server = new ApolloServer({
      typeDefs: [userTypeDefs, bookTypeDefs],
      resolvers,
    })
    

    请注意,如果您还想拆分单个类型的字段定义,则需要使用类型扩展语法。例如:

    const typeDefsA = gql`
      type Query {
        users: [User!]!
      }
    `
    const typeDefsB = gql`
      extend type Query {
        books: [Book!]!
      }
    `
    const typeDefsC = gql`
      extend type Query {
        posts: [Post!]!
      }
    `
    

    以上将合并为一个Query 类型。您可以拥有任意数量的扩展,但您要扩展的类型必须存在(即,您不能只有三个 extend type Query 定义)。牢记这一点,我通常会创建一组“基本”类型定义,例如:

    type Query
    
    type Mutation
    

    那么我所有的其他类型定义都可以扩展这些类型。请注意,因为这些“基本”类型没有任何字段,所以我们根本不使用大括号(一组空的大括号会导致语法错误!)。

    解析器

    您的解析器映射是一个普通的 JavaScript 对象,因此将其拆分很简单。

    const resolversA = {
      Query: {
        users: () => {...},
      }
    }
    
    const resolversB = {
      Query: {
        books: () => {...},
      }
    }
    

    但是,如果您尝试使用 Object.assign 或扩展语法组合这些解析器映射,您将会受到伤害,因为任何公共属性(如 Query)都将被每个对象覆盖。所以不要这样做:

    const resolvers = {
      ...resolversA,
      ...resolversB,
    }
    

    相反,您希望深度合并对象,以便所有子属性(及其属性等)也被合并。我建议使用lodash,但您可以使用任意数量的实用程序。

    const resolvers = _.merge({}, resolversA, resolversB)
    

    把它们放在一起

    您的代码可能如下所示:

    userTypeDefs.ts

    export default gql`
    type User {
      id: ID!
      username: String!
      books: [Book!]!
    }
    
    extend type Query {
      users: [User!]!
    }
    `
    

    bookTypeDefs.ts

    export default gql`
    type Book {
      id: ID!
      title: String!
      author: User!
    }
    
    extend type Query {
      books: [Book!]!
    }
    `
    

    userResolvers.ts

    export default {
      Query: {
        users: () => {...},
      },
      User: {
        books: () => {...},
      },
    }
    

    bookResolvers.ts

    export default {
      Query: {
        books: () => {...},
      },
      Book: {
        author: () => {...},
      },
    }
    

    index.ts

    import userTypeDefs from '...'
    import userResolvers from '...'
    import bookTypeDefs from '...'
    import bookResolvers from '...'
    
    // Note: This is also a good place to put any types that are common to each "module"
    const baseTypeDefs = gql`
      type Query
    `
    
    const apollo = new ApolloServer({
      typeDefs: [baseTypeDefs, userTypeDefs, bookTypeDefs],
      resolvers: _.merge({}, userResolvers, bookResolvers)
    })
    

    【讨论】:

    • 我不太了解扩展部分,你能告诉我如何按类型和解决同一个文件吗?
    • 不知道我明白你在问什么。您到底还有什么问题?
    • 基本上我想尝试将我的解析器和类型放在一个文件中
    • 只有当您想采用像QueryMutation 这样的单一类型并将其拆分到多个文件时,才需要类型扩展。您不能多次定义Query,但可以添加extend 关键字将定义变为扩展。
    • 这是spec 供参考。
    【解决方案2】:

    我不知道,这样做是否是好方法,但你可以这样做。

    
    const typeDefA = `
       name: String!
       email: String!
       phone: String!
    `
    
    const RootTypeDef = gql`
        ${typeDefA}
    
        type Query {
            users: [User]
        }
    `;
    

    您可以取出用户模式或任何其他模式并将其存储在普通变量中,然后将其添加为根模式中的变量。

    请告诉我,这是否是好的做法。

    【讨论】:

      猜你喜欢
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      • 2023-02-03
      • 2016-03-17
      • 2019-08-01
      • 2018-06-30
      • 2018-07-31
      相关资源
      最近更新 更多