Заметные различия между buildSchema и GraphQLSchema? - PullRequest
0 голосов
/ 31 декабря 2018

Есть ли заметные различия между ними?Я заинтересован во всем - от времени выполнения и производительности при запуске до функций и различий в рабочих процессах.Документация плохо объясняет разницу и то, когда я должен использовать один над другим.

Пример в обеих версиях:

buildSchema

const { graphql, buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

const root = { hello: () => 'Hello world!' };

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

GraphQLSchema

const { graphql, GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql');

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      hello: {
        type: GraphQLString,
        resolve: () => 'Hello world!'
      }
    })
  })
});

graphql(schema, '{ hello }').then((response) => {
  console.log(response);
});

1 Ответ

0 голосов
/ 31 декабря 2018

Функция buildSchema берет схему в SDL (язык определения схемы) и возвращает объект GraphQLSchema.При наличии двух идентичных схем, генерируемых каждым методом, производительность во время выполнения будет одинаковой.Время запуска для сервера, использующего buildSchema, будет медленнее, так как при разборе SDL добавляется дополнительный шаг, который в противном случае не существовал бы - будет ли заметная разница, я не могу сказать однозначно.

Использование buildSchema, как правило, нецелесообразно, так как оно серьезно ограничивает функциональность вашей схемы.

Схема, созданная с использованием buildSchema:

  • Невозможно указать функции разрешения для отдельных полей
  • Невозможно указать свойства resolveType или isTypeOf для типов, что делает невозможным использование Unions и Interfaces
  • Невозможно использовать пользовательские скаляры

Элемент # 1 не может быть подчеркнут достаточно - buildSchema не позволяет вам указать функцию распознавателя для любого поля в вашей схеме.Это включает в себя поля для типов Query и Mutation.Примеры, использующие buildSchema, решают эту проблему, полагаясь на поведение распознавателя по умолчанию в GraphQL и передавая значение root.

По умолчанию, если в поле не указана функция resolve, GraphQL проверит родительское значение (возвращаемое распознавателем родительского поля) и (при условии, что это объект) попытается найти свойствона том родительском значении, которое соответствует имени поля.Если он находит совпадение, он разрешает поле к этому значению.Если совпадение является функцией, она сначала вызывает эту функцию, а затем преобразуется в значение, возвращаемое функцией.

В приведенном выше примере поле hello в первой схеме не имеет преобразователя,GraphQL просматривает родительское значение, которое для полей корневого уровня является значением root , которое передается. Корневое значение имеет поле с именем hello, и это функция, поэтомуон вызывает функцию, а затем преобразуется в значение, возвращаемое функцией.Вы можете добиться того же эффекта, просто сделав свойство hello String вместо функции.

Учитывая вышеизложенное, два примера в вопросе на самом деле не одинаковы,Скорее, нам пришлось бы изменить вторую схему, как это, чтобы она была эквивалентной:

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      hello: {
        type: GraphQLString,
      }
    })
  })
});

const root = { hello: () => 'Hello world!' };

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

Хотя передача резолвера через корень - это хитрый трюк, опять же, он работает только для полей корневого уровня (например,поля типов Query, Mutation или Subscription).Если вы хотите предоставить распознаватель для поля другого типа, сделать это невозможно, используя buildSchema.

Итог: не используйте buildSchema.

Но я хотел использовать SDL!

И вы все еще можете! Но ... не делайте этого с помощью vanilla GraphQL.js.Вместо этого, если вы хотите использовать SDL для генерации вашей схемы, вам следует либо использовать graphql-tools 'makeExecutableSchema, либо использовать более полное решение, такое как apollo-server, которое использует makeExecutableSchema под капотом.makeExecutableSchema позволяет вам определять схему с использованием SDL, а также предоставляет отдельный объект resolvers.Таким образом, вы можете сделать:

const typeDefs = `
  type Query {
    hello: String
  }
`

const resolvers = {
  Query: {
    hello: () => 'Hello!',
  },
}

const schema = makeExecutableSchema({ typeDefs, resolvers })

Разница в том, что, в отличие от buildSchema, вы также можете предоставлять преобразователи для других типов и даже предоставлять resolveType свойства для ваших интерфейсов или объединений.

const resolvers = {
  Query: {
    animals: () => getAnimalsFromDB(),
  }
  Animal: {
    __resolveType: (obj) => obj.constructor.name
  },
  Cat: {
    owner: (cat) => getOwnerFromDB(cat.ownerId),
  }
}

Используя makeExecutableSchema, вы также можете реализовывать собственные скаляры и директивы схемы, легко настраивать различные правила проверки схемы и даже разрешать реализующим типам наследовать средства распознавания от их интерфейсов.Хотя очень важно понять основы GraphQL.js и как сгенерировать базовую схему с помощью конструктора GraphQLSchema, makeExecutableSchema является более полным и гибким решением, которое должно быть выбрано для большинства проектов. Подробнее см. В документах .

ОБНОВЛЕНИЕ

Если вы склонны использовать buildSchema, на самом деле можно обойти невозможность предоставления преобразователей для некорневых типов с помощью классов ES6.Проверьте этот пример схемы .Это не устраняет все другие ограничения buildSchema, но делает его более приемлемым.

...