Разрешить все поля в одном распознавателе VS поле разрешения в каждом распознавателе - PullRequest
0 голосов
/ 11 сентября 2018

Вот мой 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 в независимом преобразователе.

Я нахожу и resovlers1, и resolvers2 отлично работает.Я могу получить правильный ответ, как это:

{
  "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"
        }
      }
    ]
  }
}

Какая разница между ними?Являются ли эти два способа правильными?Если нет, то почему?

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

resolver1 - компромисс сложности для производительности.Основной аргумент для resolver one состоит в том, что базы данных обычно имеют объединения, которые resolver2 не может использовать.Запрос book + author может, например, быть выражен одним оператором SQL.Это огромное преимущество в производительности по сравнению с версией 2 даже с Dataloader.Теперь можно утверждать, что мы не знаем, нужно ли вообще поле автора.Но мы можем узнать это, используя аргумент resolveInfo.Можно написать функцию, которая быстро проверяет resolInfo и сообщает нам, присутствует ли поле в подвыборе:

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');
}

Это, вероятно, будет более производительным в два раза.На самом деле многие компании делают это, потому что производительность иногда является ключевой.Если пример усложняется, то сложность значительно возрастает, и я бы не стал делать такую ​​оптимизацию, если бы сначала не определил ее как узкое место.С другой стороны, существует множество проектов, работающих на «нативном GraphQL», что означает, что они превращают запросы GraphQL непосредственно в запросы к базе данных.

0 голосов
/ 11 сентября 2018

resolver2 лучше, потому что он не будет делать бесполезные вызовы в базу данных, если вы не включите author в свой запрос.

...