在一个解析器 V.S 中解析所有字段。每个解析器中的解析字段

Resolve all fields in one resolver V.S. resolve field in each resolver

这是我的 typeDefs:

const typeDefs: string = `
  type Book {
    id: ID!
    title: String
    authorId: ID!
    author: User
  }

  type User {
    id: ID!
    name: String
  }

  type Query {
    books: [Book]!
  }
`;

export { typeDefs };

resolvers:

import { IResolvers } from 'graphql-tools';
import { IBook } from './db';

const resolvers1: IResolvers = {
  Query: {
    books: (_, args, { db }): Promise<IBook[]> => {
      return db.books.map(book => {
        book.author = db.users.find(user => book.authorId === user.id);
        return book;
      });
    }
  }
};

const resolvers2: IResolvers = {
  Query: {
    books: (_, args, { db }): Promise<IBook[]> => {
      return db.books;
    }
  },
  Book: {
    author: (book, args, { db }) => {
      return db.users.find(user => book.authorId === user.id);
    }
  }
};

export { resolvers1, resolvers2 };

resolvers1 内,它解析 Book 的所有字段。 (将 author 字段添加到 book

resolvers2内,它在独立解析器中解析Book的每个字段。

我发现 resovlers1resolvers2 都能正常工作。我可以得到这样的正确响应:

{
  "data": {
    "books": [
      {
        "id": "02wDZbBuMi",
        "title": "Ea repellendus",
        "authorId": "hhP2TtobM",
        "author": {
          "id": "hhP2TtobM",
          "name": "Mrs. Destiney Kerluke"
        }
      },
      {
        "id": "tC3uPfKfUZ",
        "title": "Consectetur fugit",
        "authorId": "k9IHZAtld8",
        "author": {
          "id": "k9IHZAtld8",
          "name": "Mr. Rene Heidenreich"
        }
      }
    ]
  }
}

它们有什么区别?这两种方式正确吗?如果不是,为什么?

resolver2 更好,因为如果您不在请求中包含 author,它不会对数据库进行无用的调用。

resolver1 是复杂性与性能的权衡。解析器一的主要论点是数据库通常具有 resolver2 无法使用的连接。例如,书 + 作者查询可以用单个 SQL 语句表示。这是一个 巨大的 性能优势,即使使用 Dataloader 也比版本 2 更好。现在有人可能会争辩说我们甚至不知道是否需要 author 字段。但是我们可以使用 resolveInfo 参数来了解这一点。可以编写一个函数来快速检查 resolveInfo 并告诉我们子选择中是否存在字段:

hasSelection(fieldName: string, resolveInfo: GraphQLResolveInfo): boolean

然后我们可以使用这个函数来检查我们是否应该进行连接。

books: (_, args, { db }, resolveInfo): Promise<IBook[]> => {
  if (hasSelection('author', resolveInfo)) {
    // Just an example, there is some more transformation needed
    return db.query('SELECT ... FROM book JOIN author ON book.authorId = author.id');
  }
  return db.query('SELECT ... FROM book');
}

这可能会提高两倍的性能。实际上有很多公司这样做,因为有时性能很关键。如果示例变得更复杂,那么复杂性会显着增加,如果不首先将其确定为瓶颈,我不会进行此类优化。另一方面,有很多项目在 "native GraphQL" 上工作,这意味着他们正在将 GraphQL 查询直接转换为数据库查询。