задний план
В июле наша фронтенд-команда продвигала внедрение системы типа toB.Так как серверную часть также берут на себя наши фронтенд-инженеры, мы имеем право высказаться в выборе серверной технологии, и мы выбрали API.GraphQL. В этой статье будут описаны некоторые мои мысли об изучении GraphQL как технологии.
Какую проблему решает GraphQL
Чтобы изучить новую технологию, вы должны сначала понять предметную область. В сообществе есть большое количество статей, сравнивающих GraphQL и традиционные API-решения (включая REST API).В заключение можно сказать, что у традиционных API есть следующие проблемы:
- Количество интерфейсов имеет высокие затраты на обслуживание: количество интерфейсов обычно определяется количеством бизнес-сцен.Чтобы свести к минимуму количество интерфейсов, серверные инженеры обычно делают абстракцию для бизнеса, сначала создают небольшой интерфейс данных с небольшими детализация, а затем в соответствии с бизнес-сценарием Объединить, выставить бизнес-интерфейс наружу, даже если сервер подвергается воздействию внешнего интерфейса, потому что бизнес всегда меняется.
- Стоимость расширения интерфейса высока: с учетом пропускной способности мы требуем, чтобы интерфейс возвращал как можно меньше полей, а на стороне ПК обычно требуется отображать больше полей; учитывая производительность первого экрана, мы также требуем, чтобы интерфейс быть объединены, традиционный API отвечает этим требованиям Оба терминала находятся на реконструкции, и стоимость высока.
- Формат данных ответа интерфейса непредсказуем: поскольку документы интерфейса почти всегда не обновляются вовремя, фронтенд-инженеры не могут предсказать формат данных ответа интерфейса, что влияет на ход разработки интерфейса.
В ответ на вышеуказанные проблемы GraphQL предоставляет относительно полное решение.
Как GraphQL решает проблемы
Далее объясню идею GraphQL для решения задачи на примере запроса клиента: запросить список членов команды по полу, вернутьid
,gender
,name
,nickName
, Процесс обработки GraphQL выглядит следующим образом:
Параметры запроса будут преобразованы клиентом GraphQL в клиентскую схему перед отправкой на сервер.Эта схема фактически является разделомquery
Строка в начале описывает запрос клиента на данные: какой метод вызывать, какие параметры передавать и какие поля возвращать. После того, как сервер получает эту схему, он получает параметры запроса через предопределенную схему сервера и выполняет соответствующиеresolve
Функции предоставляют услуги данных. Весь процесс можно представить как процесс поедания шведского стола: серверная схема похожа на буфетную линию, где размещается вся еда, которую мы можем предоставить, клиентская схема описывает еду, которую мы хотим съесть, и мы можем ее получить. спрос.
В этот момент любопытные студенты, возможно, начали задумываться над этим вопросом: схема клиента по сути представляет собой строку, как сервер распознает эту строку и отвечает на нее?
graphql-js
Распознавание клиентских схем и реагирование на них зависит от официальной библиотеки классов.graphql-jsПосле того, как сервер получит клиентскую строку схемы, она будет обработана следующим образом:
- фаза синтаксического анализа
Чтобы определить схему клиента,
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, и процесс разработки больше не зависит от документа интерфейса:
Чем занимается сообщество 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.