如何在 Apollo Server 中将类型定义和解析器拆分为单独的文件

9 typescript graphql graphql-js apollo-server

索引.ts:

  const server = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req, res }: any) => ({ req, res })
  });
Run Code Online (Sandbox Code Playgroud)

用户架构.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!
  }
`;
Run Code Online (Sandbox Code Playgroud)

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;
      }
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*den 27

类型定义

ApolloServer构造函数可以接受只是一个数组,而不是DocumentNode对象。因此,您可以执行以下操作:

const server = new ApolloServer({
  typeDefs: [userTypeDefs, bookTypeDefs],
  resolvers,
})
Run Code Online (Sandbox Code Playgroud)

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

const typeDefsA = gql`
  type Query {
    users: [User!]!
  }
`
const typeDefsB = gql`
  extend type Query {
    books: [Book!]!
  }
`
const typeDefsC = gql`
  extend type Query {
    posts: [Post!]!
  }
`
Run Code Online (Sandbox Code Playgroud)

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

type Query

type Mutation
Run Code Online (Sandbox Code Playgroud)

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

解析器

您的解析器映射是一个普通的 JavaScript 对象,因此将其拆分是微不足道的。

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

const resolversB = {
  Query: {
    books: () => {...},
  }
}
Run Code Online (Sandbox Code Playgroud)

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

const resolvers = {
  ...resolversA,
  ...resolversB,
}
Run Code Online (Sandbox Code Playgroud)

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

const resolvers = _.merge({}, resolversA, resolversB)
Run Code Online (Sandbox Code Playgroud)

把这一切放在一起

您的代码可能如下所示:

用户类型定义文件

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

extend type Query {
  users: [User!]!
}
`
Run Code Online (Sandbox Code Playgroud)

bookTypeDefs.ts

export default gql`
type Book {
  id: ID!
  title: String!
  author: User!
}

extend type Query {
  books: [Book!]!
}
`
Run Code Online (Sandbox Code Playgroud)

userResolvers.ts

export default {
  Query: {
    users: () => {...},
  },
  User: {
    books: () => {...},
  },
}
Run Code Online (Sandbox Code Playgroud)

bookResolvers.ts

export default {
  Query: {
    books: () => {...},
  },
  Book: {
    author: () => {...},
  },
}
Run Code Online (Sandbox Code Playgroud)

索引.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)
})
Run Code Online (Sandbox Code Playgroud)