Release Notes & Upgrade Guides > Руководство по переходу на валидацию GraphQL

Руководство по переходу на валидацию GraphQL

Reading time: 7 min

Вскоре graph-node будет поддерживать 100-процентное покрытие [спецификации GraphQL Validation] (https://spec.graphql.org/June2018/#sec-Validation).

Предыдущие версии graph-node не поддерживали все валидации и предоставляли более обтекаемые ответы, поэтому в случаях неоднозначности graph-node игнорировал недопустимые компоненты операций GraphQL.

Поддержка валидации GraphQL является основой для будущих новых функций и производительности в масштабе The Graph Network.

Это также обеспечит детерминизм ответов на запросы, что является ключевым требованием в сети The Graph.

Включение валидации GraphQL нарушит работу некоторых существующих запросов, отправленных в API The Graph.

Чтобы выполнить эти валидации, следуйте руководству по миграции.

⚠️ Если Вы не перенесете свои запросы до развертывания валидаций, они будут возвращать ошибки и, возможно, повредят ваши интерфейсы/клиенты.

Руководство по миграции

Ссылка на этот раздел

Вы можете использовать инструмент миграции CLI, чтобы найти любые проблемы в операциях GraphQL и исправить их. В качестве альтернативы вы можете обновить конечную точку своего клиента GraphQL, чтобы использовать конечную точку https://api-next.thegraph.com/subgraphs/name/$GITHUB_USER/$SUBGRAPH_NAME. Проверка запросов на этой конечной точке поможет Вам обнаружить проблемы в Ваших запросах.

Не все субграфы нужно будет переносить, если Вы используете GraphQL ESlint или GraphQL Code Generator, они уже гарантируют корректность Ваших запросов.

CLI-инструмент миграции

Ссылка на этот раздел

Большинство ошибок операций GraphQL можно обнаружить в Вашей кодовой базе заранее.

По этой причине мы обеспечиваем беспрепятственный процесс валидации Ваших операций GraphQL во время разработки или в CI.

@graphql-validate/cli — это простой инструмент командной строки, который помогает проверять операции GraphQL по заданной схеме.

Начало работы

Ссылка на этот раздел

Вы можете запустить инструмент следующим образом:

npx @graphql-validate/cli -s https://api-next.thegraph.com/subgraphs/name/$GITHUB_USER/$SUBGRAPH_NAME -o *.graphql

Примечания:

  • Установите или замените $GITHUB_USER, $SUBGRAPH_NAME соответствующими значениями. Например: artblocks/art-blocks
  • Предоставленный URL-адрес схемы предварительного просмотра (https://api-next.thegraph.com/) сильно ограничен по скорости и будет удален после того, как все пользователи перейдут на новую версию. Не используйте его в рабочей среде.
  • Операции идентифицируются в файлах со следующими расширениями [.graphql,] (https://www.graphql-tools.com/docs/schema-loading#graphql-file-loader) .ts, .tsx, .js, jsx (-o option).

Инструмент CLI [@graphql-validate/cli](https://github.com/saihaj/graphql-validate) будет выводить любые ошибки операций GraphQL следующим образом:

Error output from CLI

Для каждой ошибки Вы найдете описание, путь к файлу и его положение, а также ссылку на пример решения (см. следующий раздел).

Выполняйте локальные запросы по схеме предварительного просмотра

Ссылка на этот раздел

Мы предоставляем конечную точку https://api-next.thegraph.com/, которая запускает версию graph-node с включенной валидацией.

Вы можете опробовать запросы, отправив их по адресу:

  • https://api-next.thegraph.com/subgraphs/id/<Qm...>

или

  • https://api-next.thegraph.com/subgraphs/name/<GITHUB_USER>/<SUBGRAPH_NAME>

Чтобы работать с запросами, которые были помечены как имеющие ошибки валидации, Вы можете использовать свой любимый инструмент запросов GraphQL, например Altair или GraphiQL и попробовать свой запрос. Эти инструменты также будут отмечать ошибки в своем пользовательском интерфейсе еще до того, как Вы их запустите.

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

Ссылка на этот раздел

Ниже Вы найдете все ошибки валидации GraphQL, которые могут возникнуть в Ваших операциях GraphQL.

Переменные, операции, фрагменты или аргументы GraphQL должны быть уникальными

Ссылка на этот раздел

Мы применили правила, гарантирующие, что операция включает уникальный набор переменных, операций, фрагментов и аргументов GraphQL.

Операция GraphQL действительна только в том случае, если она не содержит какой-либо неоднозначности.

Для этого нам нужно убедиться, что некоторые компоненты в Вашей операции GraphQL уникальны.

Ниже приведен пример нескольких недопустимых операций, нарушающих эти правила:

Повторяющееся имя запроса (#UniqueOperationNamesRule)

# Следующая операция нарушила UniqueOperationName
# правило, так как у нас одна операция с 2-мя запросами
# с тем же именем
query myData {
id
}
query myData {
name
}

Решение:

query myData {
id
}
query myData2 {
# rename the second query
name
}

Повторяющееся имя фрагмента (#UniqueFragmentNamesRule)

# Следующая операция нарушила UniqueFragmentName
# правило.
query myData {
id
...MyFields
}
fragment MyFields {
metadata
}
fragment MyFields {
name
}

Решение:

query myData {
id
...MyFieldsName
...MyFieldsMetadata
}
fragment MyFieldsMetadata { # присвоить фрагменту уникальное имя
metadata
}
fragment MyFieldsName { # присвоить фрагменту уникальное имя
name
}

Повторяющееся имя переменной (#UniqueVariableNamesRule)

# Следующая операция нарушает UniqueVariables
query myData($id: String, $id: Int) {
id
...MyFields
}

Решение:

query myData($id: String) {
# сохранить соответствующую переменную (здесь: `$id: String`)
id
...MyFields
}

Повторяющееся имя аргумента (#UniqueArgument)

# Следующая операция нарушила UniqueArguments
query myData($id: ID!) {
userById(id: $id, id: "1") {
id
}
}

Решение:

query myData($id: ID!) {
userById(id: $id) {
id
}
}

Повторяющийся анонимный запрос (#LoneAnonymousOperationRule)

Кроме того, использование двух анонимных операций нарушит правило LoneAnonymousOperation из-за конфликта в структуре ответа:

# Это приведет к ошибке, если выполнить их вместе в
# одной операции со следующими двумя запросами:
query {
someField
}
query {
otherField
}

Решение:

query {
someField
otherField
}

Или назовите эти два запроса:

query FirstQuery {
someField
}
query SecondQuery {
otherField
}

Перекрывающиеся поля

Ссылка на этот раздел

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

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

Вот несколько примеров недопустимых операций, нарушающих это правило:

Псевдонимы конфликтующих полей (#OverlappingFieldsCanBeMergedRule)

# Псевдонимы полей могут вызвать конфликты либо с
# другими псевдонимами или другими полями, существующими в
# схеме GraphQL.
query {
dogs {
name: nickname
name
}
}

Решение:

query {
dogs {
name: nickname
originalName: name # alias the original `name` field
}
}

Конфликтующие поля с аргументами (#OverlappingFieldsCanBeMergedRule)

# Разные аргументы могут привести к разным данным,
# поэтому мы не можем предположить, что поля будут одинаковыми.
query {
dogs {
doesKnowCommand(dogCommand: SIT)
doesKnowCommand(dogCommand: HEEL)
}
}

Решение:

query {
dogs {
knowsHowToSit: doesKnowCommand(dogCommand: SIT)
knowsHowToHeel: doesKnowCommand(dogCommand: HEEL)
}
}

Кроме того, в более сложных случаях использования Вы можете нарушить это правило, используя два фрагмента, которые могут вызвать конфликт в ожидаемом в конечном итоге наборе:

query {
# В конце концов, у нас есть два определения "x", указывающие
# на разные поля!
...A
...B
}
fragment A on Type {
x: a
}
fragment B on Type {
x: b
}

Кроме того, директивы GraphQL на стороне клиента, такие как @skip и @include, могут привести к неоднозначности, например:

fragment mergeSameFieldsWithSameDirectives on Dog {
name @include(if: true)
name @include(if: false)
}

Подробнее об алгоритме можно прочитать здесь.

Неиспользуемые переменные или фрагменты

Ссылка на этот раздел

Операция GraphQL также считается действительной, только если используются все определенные в операции компоненты (переменные, фрагменты).

Вот несколько примеров операций GraphQL, которые нарушают эти правила:

Неиспользуемая переменная (#NoUnusedVariablesRule)

# Неверно, потому что $someVar никогда не используется.
query something($someVar: String) {
someData
}

Решение:

query something {
someData
}

Неиспользуемый фрагмент (#NoUnusedFragmentsRule)

# Неверно, так как фрагмент AllFields никогда не используется.
query something {
someData
}
fragment AllFields { # unused :(
name
age
}

Решение:

# Неверно, так как фрагмент AllFields никогда не используется.
query something {
someData
}
# удалить фрагмент `AllFields`

Недопустимый или отсутствующий набор элементов выбора (#ScalarLeafsRule)

Ссылка на этот раздел

Кроме того, выбор поля GraphQL действителен только в том случае, если подтверждено следующее:

  • Поле объекта должно иметь заданный набор выбора.
  • Краевое поле (скалярное, перечислимое) не должно иметь заданного набора выбора.

Вот несколько примеров нарушения этих правил со следующей схемой:

type Image {
url: String!
}
type User {
id: ID!
avatar: Image!
}
type Query {
user: User!
}

Недопустимый набор выбора

query {
user {
id { # Неверно, так как "id" имеет тип ID и не имеет подполей
}
}
}

Решение:

query {
user {
id
}
}

Отсутствует набор выбора

query {
user {
id
image # `image` требует набора выбора для подполей!
}
}

Решение:

query {
user {
id
image {
src
}
}
}

Неверные значения аргументов (#VariablesInAllowedPositionRule)

Ссылка на этот раздел

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

Вот несколько примеров недопустимых операций, нарушающих эти правила:

query purposes {
# Если в схеме "name" определено как "String",
# этот запрос не пройдёт валидацию.
purpose(name: 1) {
id
}
}
# Это также может произойти, если определена неверная переменная:
query purposes($name: Int!) {
# Если "name" определено в схеме как `String`,
# этот запрос не пройдёт валидацию, потому что
# используемая переменная имеет тип `Int`
purpose(name: $name) {
id
}
}

Неизвестный тип, переменная, фрагмент или директива (#UnknownX)

Ссылка на этот раздел

API GraphQL вызовет ошибку, если используется какой-либо неизвестный тип, переменная, фрагмент или директива.

Эти неизвестные ссылки необходимо исправить:

  • переименуйте, если это опечатка
  • в противном случае удалите

Фрагмент: недопустимый спред или определение

Ссылка на этот раздел

Неверный разворот фрагмента (#PossibleFragmentSpreadsRule)

Фрагмент не может быть распространен на неприменимый тип.

Например, мы не можем применить фрагмент Cat к типу Dog:

query {
dog {
...CatSimple
}
}
fragment CatSimple on Cat {
# ...
}

Недопустимое определение фрагмента (#FragmentsOnCompositeTypesRule)

Все фрагменты должны быть определены (используя on ...) для составного типа, короче говоря: для объекта, интерфейса или объединения.

Следующие примеры недопустимы, так как определение фрагментов на скалярах недопустимо.

fragment fragOnScalar on Int {
# мы не можем определить фрагмент на скаляре (`Int`)
something
}
fragment inlineFragOnScalar on Dog {
... on Boolean {
# `Boolean` не является подтипом `Dog`
somethingElse
}
}

Применение директив

Ссылка на этот раздел

Директива не может быть использована в данном месте (#KnownDirectivesRule)

Можно использовать только директивы GraphQL ("@..."), поддерживаемые The Graph API.

Вот пример с директивами, поддерживаемыми GraphQL:

query {
dog {
name @include(true)
age @skip(true)
}
}

Примечание: @stream, @live, @defer не поддерживаются.

Директива может быть использована в этом месте только один раз (#UniqueDirectivesPerLocationRule)

Директивы, поддерживаемые The Graph, можно использовать только один раз в каждом месте.

Следующее является недопустимым (и избыточным):

query {
dog {
name @include(true) @include(true)
}
}
Редактировать страницу

Предыдущий
Руководство по миграции AssemblyScript
Следующий
Подпотоки
Редактировать страницу