How to split type definitions and resolvers into separate files in Apollo Server

前端 未结 1 1003
走了就别回头了
走了就别回头了 2021-01-02 18:12

index.ts:

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

User

相关标签:
1条回答
  • 2021-01-02 18:46

    Type Definitions

    The ApolloServer constructor can accept an array instead of just the one DocumentNode object. So you can do something like:

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

    Note that if you want to split up an individual type's field definitions as well, you'll need to use type extension syntax. For example:

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

    The above will be combined into a single Query type. You can have as many extensions as you want, but the type you're extending must exist (i.e., you can't have just three extend type Query definitions). Keeping this in mind, I usually create a "base" set of type definitions like:

    type Query
    
    type Mutation
    

    Then all my other type definitions can extend these types. Notice that because these "base" types don't have any fields, we don't use curly brackets at all (an empty set of curly brackets will result in a syntax error!).

    Resolvers

    Your resolver map is a plain JavaScript object, so splitting it it up is trivial.

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

    However, if you attempt to combine these resolver maps using Object.assign or spread syntax, you'll be hurting because any common properties (like Query) will be overridden by each object. So do not do this:

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

    Instead, you want to deep merge the objects, so that any child properties (and their properties, and so on) are merged as well. I recommend using lodash but there's any number of utilities you can use.

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

    Putting it all together

    Your code might look something like this:

    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)
    })
    
    0 讨论(0)
提交回复
热议问题