7 минуты
GraphQL Validations Migration Guide
Вскоре 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
. Проверка запросов на этой конечной точке поможет Вам обнаружить проблемы в Ваших запросах.
Not all Subgraphs will need to be migrated, if you are using GraphQL ESlint or GraphQL Code Generator, they already ensure that your queries are valid.
CLI-инструмент миграции
Большинство ошибок операций GraphQL можно обнаружить в Вашей кодовой базе заранее.
По этой причине мы обеспечиваем беспрепятственный процесс валидации Ваших операций GraphQL во время разработки или в CI.
@graphql-validate/cli
— это простой инструмент командной строки, который помогает проверять операции GraphQL по заданной схеме.
Начало работы
Вы можете запустить инструмент следующим образом:
1npx @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
Инструмент CLI [@graphql-validate/cli](https://github.com/saihaj/graphql-validate)
будет выводить любые ошибки операций GraphQL следующим образом:

Для каждой ошибки Вы найдете описание, путь к файлу и его положение, а также ссылку на пример решения (см. следующий раздел).
Выполняйте локальные запросы по схеме предварительного просмотра
Мы предоставляем конечную точку 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)
1# Следующая операция нарушила UniqueOperationName2# правило, так как у нас одна операция с 2-мя запросами3# с тем же именем4query myData {5 id6}78query myData {9 name10}
Решение:
1query myData {2 id3}45query myData2 {6 # rename the second query7 name8}
Повторяющееся имя фрагмента (#UniqueFragmentNamesRule)
1# Следующая операция нарушила UniqueFragmentName2# правило.3query myData {4 id5 ...MyFields6}78fragment MyFields {9 metadata10}1112fragment MyFields {13 name14}
Решение:
1query myData {2 id3 ...MyFieldsName4 ...MyFieldsMetadata5}67fragment MyFieldsMetadata { # присвоить фрагменту уникальное имя8 metadata9}1011fragment MyFieldsName { # присвоить фрагменту уникальное имя12 name13}
Повторяющееся имя переменной (#UniqueVariableNamesRule)
1# Следующая операция нарушает UniqueVariables2query myData($id: String, $id: Int) {3 id4 ...MyFields5}
Решение:
1query myData($id: String) {2 # сохранить соответствующую переменную (здесь: `$id: String`)3 id4 ...MyFields5}
Повторяющееся имя аргумента (#UniqueArgument)
1# Следующая операция нарушила UniqueArguments2query myData($id: ID!) {3 userById(id: $id, id: "1") {4 id5 }6}
Решение:
1query myData($id: ID!) {2 userById(id: $id) {3 id4 }5}
Повторяющийся анонимный запрос (#LoneAnonymousOperationRule)
Кроме того, использование двух анонимных операций нарушит правило LoneAnonymousOperation из-за конфликта в структуре ответа:
1# Это приведет к ошибке, если выполнить их вместе в2# одной операции со следующими двумя запросами:3query {4 someField5}67query {8 otherField9}
Решение:
1query {2 someField3 otherField4}
Или назовите эти два запроса:
1query FirstQuery {2 someField3}45query SecondQuery {6 otherField7}
Перекрывающиеся поля
Набор выбора GraphQL считается допустимым, только если он правильно разрешает конечный набор результатов.
Если конкретный набор элементов или поле создают неоднозначность либо из-за выбранного поля, либо из-за используемых аргументов, служба GraphQL не сможет валидировать операцию.
Вот несколько примеров недопустимых операций, нарушающих это правило:
Псевдонимы конфликтующих полей (#OverlappingFieldsCanBeMergedRule)
1# Псевдонимы полей могут вызвать конфликты либо с2# другими псевдонимами или другими полями, существующими в3# схеме GraphQL.4query {5 dogs {6 name: nickname7 name8 }9}
Решение:
1query {2 dogs {3 name: nickname4 originalName: name # alias the original `name` field5 }6}
Конфликтующие поля с аргументами (#OverlappingFieldsCanBeMergedRule)
1# Разные аргументы могут привести к разным данным,2# поэтому мы не можем предположить, что поля будут одинаковыми.3query {4 dogs {5 doesKnowCommand(dogCommand: SIT)6 doesKnowCommand(dogCommand: HEEL)7 }8}
Решение:
1query {2 dogs {3 knowsHowToSit: doesKnowCommand(dogCommand: SIT)4 knowsHowToHeel: doesKnowCommand(dogCommand: HEEL)5 }6}
Кроме того, в более сложных случаях использования Вы можете нарушить это правило, используя два фрагмента, которые могут вызвать конфликт в ожидаемом в конечном итоге наборе:
1query {2 # В конце концов, у нас есть два определения "x", указывающие3 # на разные поля!4 ...A5 ...B6}78fragment A on Type {9 x: a10}1112fragment B on Type {13 x: b14}
Кроме того, директивы GraphQL на стороне клиента, такие как @skip
и @include
, могут привести к неоднозначности, например:
1fragment mergeSameFieldsWithSameDirectives on Dog {2 name @include(if: true)3 name @include(if: false)4}
Подробнее об алгоритме можно прочитать здесь.
Неиспользуемые переменные или фрагменты
Операция GraphQL также считается действительной, только если используются все определенные в операции компоненты (переменные, фрагменты).
Вот несколько примеров операций GraphQL, которые нарушают эти правила:
Неиспользуемая переменная (#NoUnusedVariablesRule)
1# Неверно, потому что $someVar никогда не используется.2query something($someVar: String) {3 someData4}
Решение:
1query something {2 someData3}
Неиспользуемый фрагмент (#NoUnusedFragmentsRule)
1# Неверно, так как фрагмент AllFields никогда не используется.2query something {3 someData4}56fragment AllFields { # unused :(7 name8 age9}
Решение:
1# Неверно, так как фрагмент AllFields никогда не используется.2query something {3 someData4}56# удалить фрагмент `AllFields`
Недопустимый или отсутствующий набор элементов выбора (#ScalarLeafsRule)
Кроме того, выбор поля GraphQL действителен только в том случае, если подтверждено следующее:
- Поле объекта должно иметь заданный набор выбора.
- Краевое поле (скалярное, перечислимое) не должно иметь заданного набора выбора.
Вот несколько примеров нарушения этих правил со следующей схемой:
1type Image {2 url: String!3}45type User {6 id: ID!7 avatar: Image!8}910type Query {11 user: User!12}
Недопустимый набор выбора
1query {2 user {3 id { # Неверно, так как "id" имеет тип ID и не имеет подполей45 }6 }7}
Решение:
1query {2 user {3 id4 }5}
Отсутствует набор выбора
1query {2 user {3 id4 image # `image` требует набора выбора для подполей!5 }6}
Решение:
1query {2 user {3 id4 image {5 src6 }7 }8}
Неверные значения аргументов (#VariablesInAllowedPositionRule)
Операции GraphQL, которые передают жестко запрограммированные значения в аргументы, должны быть допустимыми на основе значения, определенного в схеме.
Вот несколько примеров недопустимых операций, нарушающих эти правила:
1query purposes {2 # Если в схеме "name" определено как "String",3 # этот запрос не пройдёт валидацию.4 purpose(name: 1) {5 id6 }7}89# Это также может произойти, если определена неверная переменная:1011query purposes($name: Int!) {12 # Если "name" определено в схеме как `String`,13 # этот запрос не пройдёт валидацию, потому что14 # используемая переменная имеет тип `Int`15 purpose(name: $name) {16 id17 }18}
Неизвестный тип, переменная, фрагмент или директива (#UnknownX)
API GraphQL вызовет ошибку, если используется какой-либо неизвестный тип, переменная, фрагмент или директива.
Эти неизвестные ссылки необходимо исправить:
- переименуйте, если это опечатка
- в противном случае удалите
Фрагмент: недопустимый спред или определение
Неверный разворот фрагмента (#PossibleFragmentSpreadsRule)
Фрагмент не может быть распространен на неприменимый тип.
Например, мы не можем применить фрагмент Cat
к типу Dog
:
1query {2 dog {3 ...CatSimple4 }5}67fragment CatSimple on Cat {8 # ...9}
Недопустимое определение фрагмента (#FragmentsOnCompositeTypesRule)
Все фрагменты должны быть определены (используя on ...
) для составного типа, короче говоря: для объекта, интерфейса или объединения.
Следующие примеры недопустимы, так как определение фрагментов на скалярах недопустимо.
1fragment fragOnScalar on Int {2 # мы не можем определить фрагмент на скаляре (`Int`)3 something4}56fragment inlineFragOnScalar on Dog {7 ... on Boolean {8 # `Boolean` не является подтипом `Dog`9 somethingElse10 }11}
Применение директив
Директива не может быть использована в данном месте (#KnownDirectivesRule)
Можно использовать только директивы GraphQL (”@…”), поддерживаемые The Graph API.
Вот пример с директивами, поддерживаемыми GraphQL:
1query {2 dog {3 name @include(true)4 age @skip(true)5 }6}
Примечание: @stream
, @live
, @defer
не поддерживаются.
Директива может быть использована в этом месте только один раз (#UniqueDirectivesPerLocationRule)
Директивы, поддерживаемые The Graph, можно использовать только один раз в каждом месте.
Следующее является недопустимым (и избыточным):
1query {2 dog {3 name @include(true) @include(true)4 }5}