Анализ технологии GraphQL

база данных внешний интерфейс API GraphQL
Анализ технологии GraphQL

задний план

В июле наша фронтенд-команда продвигала внедрение системы типа toB.Так как серверную часть также берут на себя наши фронтенд-инженеры, мы имеем право высказаться в выборе серверной технологии, и мы выбрали API.GraphQL. В этой статье будут описаны некоторые мои мысли об изучении GraphQL как технологии.

Какую проблему решает GraphQL

Чтобы изучить новую технологию, вы должны сначала понять предметную область. В сообществе есть большое количество статей, сравнивающих GraphQL и традиционные API-решения (включая REST API).В заключение можно сказать, что у традиционных API есть следующие проблемы:

  • Количество интерфейсов имеет высокие затраты на обслуживание: количество интерфейсов обычно определяется количеством бизнес-сцен.Чтобы свести к минимуму количество интерфейсов, серверные инженеры обычно делают абстракцию для бизнеса, сначала создают небольшой интерфейс данных с небольшими детализация, а затем в соответствии с бизнес-сценарием Объединить, выставить бизнес-интерфейс наружу, даже если сервер подвергается воздействию внешнего интерфейса, потому что бизнес всегда меняется.
  • Стоимость расширения интерфейса высока: с учетом пропускной способности мы требуем, чтобы интерфейс возвращал как можно меньше полей, а на стороне ПК обычно требуется отображать больше полей; учитывая производительность первого экрана, мы также требуем, чтобы интерфейс быть объединены, традиционный API отвечает этим требованиям Оба терминала находятся на реконструкции, и стоимость высока.
  • Формат данных ответа интерфейса непредсказуем: поскольку документы интерфейса почти всегда не обновляются вовремя, фронтенд-инженеры не могут предсказать формат данных ответа интерфейса, что влияет на ход разработки интерфейса.

В ответ на вышеуказанные проблемы GraphQL предоставляет относительно полное решение.

Как GraphQL решает проблемы

Далее объясню идею GraphQL для решения задачи на примере запроса клиента: запросить список членов команды по полу, вернутьid,gender,name,nickName, Процесс обработки GraphQL выглядит следующим образом:

image.png

Параметры запроса будут преобразованы клиентом GraphQL в клиентскую схему перед отправкой на сервер.Эта схема фактически является разделомqueryСтрока в начале описывает запрос клиента на данные: какой метод вызывать, какие параметры передавать и какие поля возвращать. После того, как сервер получает эту схему, он получает параметры запроса через предопределенную схему сервера и выполняет соответствующиеresolveФункции предоставляют услуги данных. Весь процесс можно представить как процесс поедания шведского стола: серверная схема похожа на буфетную линию, где размещается вся еда, которую мы можем предоставить, клиентская схема описывает еду, которую мы хотим съесть, и мы можем ее получить. спрос.

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

graphql-js

Распознавание клиентских схем и реагирование на них зависит от официальной библиотеки классов.graphql-jsПосле того, как сервер получит клиентскую строку схемы, она будет обработана следующим образом:

image.png

  • фаза синтаксического анализа Чтобы определить схему клиента,graphql-jsОпределен ряд идентификаторов объектов:
export const TokenKind = Object.freeze({
    BANG: '!',
    DOLLAR: '$',
    PAREN_L: '(',
    PAREN_R: ')',
    SPREAD: '...',
    COLON: ':',
    EQUALS: '=',
    BRACKET_L: '[',
    BRACKET_R: ']',
    ...
});

И определяет спецификацию синтаксического дерева AST, которая предусматривает, что синтаксическое дерево поддерживает следующие узлы:

/**
 * The set of allowed kind values for AST nodes.
 */
export const Kind = Object.freeze({
  // Name
  NAME: 'Name',

  // Document
  DOCUMENT: 'Document',
  OPERATION_DEFINITION: 'OperationDefinition',
  VARIABLE_DEFINITION: 'VariableDefinition',
  VARIABLE: 'Variable',

  // Values
  INT: 'IntValue',
  FLOAT: 'FloatValue',
  STRING: 'StringValue',
  BOOLEAN: 'BooleanValue',
  ...
});

Используя строку функций и спецификацию синтаксического дерева AST, GraphQL Server сканирует схему клиента посимвольно (charCodeAt), и на заключительном этапе синтаксического анализа выводится результатdocument, часть после синтаксического анализа клиентской схемы в приведенном выше примере завершенаdocument:

{
  "kind":"Document",
  "definitions":[
  {
    "kind":"OperationDefinition",
    "operation":"query",
    "name":{
      "kind":"Name",
      "value":"DisplayMember",
      "loc":{
        "start":13,
        "end":26
      }
    },
    "selectionSet":{
      "kind":"SelectionSet",
      "selections":[
        {
          "kind":"Field",
          "alias":null,
          "name":{
            "kind":"Name",
            "value":"fetchByGender",
            "loc":{
              "start":37,
              "end":50
            }
          },
          "arguments":[
            {
              "kind":"Argument",
              "name":{
                "kind":"Name",
                "value":"gender",
                "loc":{
                  "start":51,
                  "end":57
                }
              },
              "value":{
                "kind":"StringValue",
                "value":"M",
                "loc":{
                  "start":59,
                  "end":62
                }
              },
              "loc":{
                "start":51,
                "end":62
              }
            }
          ],
...

Если схема клиента не соответствует спецификации AST, определенной сервером, процесс синтаксического анализа напрямую вызовет синтаксическое исключение.Syntax Error, взяв приведенный выше пример в качестве примера, я будуfetchByGender(gender: "M")изменить наfetchByGender(gender), передайте только имя параметра, а не его значение, сервер ответит:

{
    "errors":[
        {
            "message":"Syntax Error GraphQL request (3:29) Expected :, found )

2: query DisplayMember {
3: fetchByGender(gender) {
^
4: list {
",
            "locations":[
                {
                    "line":3,
                    "column":29
                }
            ]
        }
    ]
}

Структурированная информация об ошибках также является важной особенностью GraphQL, и она очень удобна для обнаружения проблем. Пока нет проблем с грамматикой, этап синтаксического анализа можно успешно завершить, а затем перейти к этапу проверки.

  • этап проверки

Этап проверки используется для проверки того, получает ли схема клиента данные способом, определенным схемой сервера, например: неверно ли имя метода для получения данных, имеют ли требуемые элементы значения и т. д. Существуют десятки диапазонов проверки. Я не могу привести примеры. Взяв приведенный выше пример в качестве примера, я буду использоватьfetchByGenderизменить наfetchByGen,fetchByGenЕсли он вообще не определен на стороне сервера, сторона сервера ответит:

{
    "errors":[
        {
            "message":"Cannot query field "fetchByGen" on type "Query". Did you mean "fetchByGender"?",
            "locations":[
                {
                    "line":3,
                    "column":9
                }
            ]
        }
    ]
}

Не только возвращает структурированное сообщение об ошибке, но и очень гуманно сообщает вам, какой правильный метод вызова. После того, как этап проверки будет пройден, он войдет в этап исполнения

  • этап выполнения

Входные данные, от которых зависит фаза выполнения: выходные данные фазы синтаксического анализаdocument, схема на стороне сервера; гдеdocumentОн точно описывает запрос клиента на данные: какой метод запрашивается, какие параметры требуются и какие поля обязательны; схема на стороне сервера описывает способ предоставления данных; на примере приведенного выше примера схема на стороне сервера необходимо определить следующим образом:

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

const dataSource = require('./dataSource');

const memType = new GraphQLObjectType({
  name: 'Male',
  description: 'A member gender is Male.',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The id of member',
    },
    name: {
      type: GraphQLString,
      description: 'The name of the character.',
    },
    nickName: {
      type: GraphQLString,
      description: 'The nickName of the character.',
    },
    gender: {
      type: GraphQLString,
      description: 'The gender of the character.',
    },
    list: {
      type: new GraphQLList(memType),
      description: 'The mems list by gender.',
    },
  })
});

const queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    fetchByGender: {
      type: memType,
      args: {
        gender: {
          description: 'gender of the human',
          type: new GraphQLNonNull(GraphQLString),
        },
      },
      resolve: (root, { gender }) => {
        // 访问数据库或三方 API 查询成员列表
        return {
          list: dataSource.getMembers(gender),
        };
      },
    },
  }),
});

module.exports = new GraphQLSchema({
  query: queryType,
  types: [memType],
});

Выполнение сервера схемыresolveфункция для получения вывода фазы выполнения:

{
    "data":{
        "fetchByGender":{
            "list":[
                {
                    "id":"1",
                    "gender":"M",
                    "name":"童开宏",
                    "nickName":"慕冥"
                }
            ]
        }
    }
}

Конечно, чтобы завершить определение схемы на стороне сервера, вам нужно изучить GraphQL.система типов, вы можете прочитать документацию по API.

технические границы

После того, как принцип ясен, нам нужно иметь четкое представление о границах технологии GraphQL:

  • Граница клиента: основная возможность состоит в том, чтобы собрать параметры запроса в строки схемы клиента в соответствии со спецификацией синтаксического дерева AST, определенной сервером.Вы можете обратиться к схеме реализации.apolloкоторый предоставилПлагин веб-пакета, конечно, есть также некоторые клиенты GraphQL, которые даже отправляют запросы Ajax, не более чем вызов других библиотек классов внизу, таких какaxiosОтправить запрос.

  • Граница сервера: основная возможность состоит в том, чтобы идентифицировать строку клиентской схемы и вызвать базовую службу данных через схему сервера, чтобы вернуть данные, которые пользователь хочет по запросу. ) и каким образом получение данных (прямое подключение к базе данных или вызов метода ORM) не является тем, о чем заботится GraphQL.

как решается проблема

Так как GraphQL описывает запрос данных через клиентскую схему, а не URL, теоретически серверу нужно выставить клиенту только адрес, что решает проблему большого количества интерфейсов и высоких затрат на обслуживание; в то же время сервер предоставляет полные поля, которые клиент может получить по запросу, и сервер не требует затрат на разработку для удовлетворения потребностей расширения интерфейса Наконец, все данные, которые может предоставить сервер, отображаются через визуальный интерфейс отладки GraphiQL, и процесс разработки больше не зависит от документа интерфейса:

image.png

Чем занимается сообщество GraphQL

GraphQL официально предоставляет основные возможности:

  • graphql-js: JavaScript-реализация концепции GraphQL, эта библиотека классов может работать в среде браузера и среде Node одновременно, принцип работы этой библиотеки классов я уже упоминал выше.
  • graphiql: улучшите процесс отладки, о котором я упоминал выше.
  • dataloader: повышение производительности и минимизация количества запросов к базе данных путем объединения запросов.
  • Relay: внешний фреймворк, который хорошо интегрирует GraphQL и React, с сильным внедрением и требует взаимодействия с GraphQL Server.

Что нам не хватает?

  • Сервер Официально поддерживается только язык JavaScript, и энтузиасты сообщества быстро реализовали концепцию GraphQL на разных языках программирования:JAVA,.NETПодождите, больше языковой поддержки, пожалуйста, проверьтеОфициальный сайт

  • клиент официально предоставленRelayРешена проблема совмещения GraphQL с React,Apollo ClientПредоставляет решения, которые интегрируются с другими интерфейсными фреймворками, такими как Vue, Angular и другими.

  • опыт разработки

    • graphql-tools: В приведенной выше схеме примера кода на стороне сервера мы помещаем определение типа (typeDefs) и определение функции-обработчика (преобразователи) в один и тот же файл, и обязанности не являются достаточно отдельными.graphql-toolsМы можем определить разные файлы из двух;

    • egg-graphql: с фреймворком Nodeeggкомбинировать, формулироватьСпецификация каталогаИ предоставить синтаксический сахар для повышения эффективности разработки;

Суммировать

Преимущества GraphQL были упомянуты выше.Он действительно решает проблемы, существующие в традиционных API, исходя из болевых точек бизнеса.Однако GraphQL также приносит некоторые новые проблемы при решении проблем.Эти проблемы в некоторой степени мешают.Популярность этой технологии:

  • Производительность базы данных: GraphQL описывает данные как огромную сеть.Теоретически клиентская схема может писать запросы на любом уровне вложенности, например:
query IAmEvil {
  author(id: "abc") {
    posts {
      author {
        posts {
          author {
            posts {
              author {
                # that could go on as deep as the client wants!
              }
            }
          }
        }
      }
    }
  }
}

Такой оператор запроса приведет к большой нагрузке на базу данных, и серверу придется это делать.ОграничениеЧтобы избежать таких проблем, это также влечет за собой дополнительные затраты на разработку.

  • Инвазивность: GraphQL больше всего выигрывает от внешнего интерфейса, но ему нужна полная поддержка сервера, особенно миграция старой системы.И сервер, и внешний интерфейс претерпевают серьезные изменения.
  • Стоимость обучения: GraphQL — это новый набор концепций, который требует, чтобы как внешние, так и внутренние студенты изучили новые знания для освоения этой технологии, что также требует больших затрат на обучение.

У любой технологии есть свои плюсы и минусы, каждый должен взвесить преимущества в соответствии со своими сценариями и сделать выбор технологии, которая подходит именно ему.

Справочная документация

Статья может быть воспроизведена по желанию, но просьба сохранитьОригинальная ссылка. Добро пожаловать!ES2049 Studio, отправьте свое резюме на caijun.hcj(at)alibaba-inc.com.