{"meta":{"title":"Формирование вызовов с помощью GraphQL","intro":"Узнайте, как выполнить проверку подлинности в API GraphQL, а затем узнайте, как создавать и выполнять запросы и изменения.","product":"API GraphQL","breadcrumbs":[{"href":"/ru/graphql","title":"API GraphQL"},{"href":"/ru/graphql/guides","title":"Guides"},{"href":"/ru/graphql/guides/forming-calls-with-graphql","title":"Вызовы форм с помощью GraphQL"}],"documentType":"article"},"body":"# Формирование вызовов с помощью GraphQL\n\nУзнайте, как выполнить проверку подлинности в API GraphQL, а затем узнайте, как создавать и выполнять запросы и изменения.\n\n## Проверка подлинности с помощью GraphQL\n\nВы можете аутентифицироваться в API GraphQL с помощью personal access token, GitHub App, или OAuth app.\n\n### Аутентификация с помощью personal access token\n\nДля аутентификации personal access tokenс помощью , следуйте шагам в [Управление личными маркерами доступа](/ru/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens). Запрашиваемые данные определяют, какие области или разрешения потребуются.\n\nНапример, выберите разрешение \"issues:read\", чтобы прочитать все проблемы в репозиториях, к которым ваш токен имеет access.\n\nВсе fine-grained personal access tokens имеют доступ к публичным репозиториям. Чтобы получить доступ к публичным репозиториям с personal access token (classic)помощью , выберите область действия \"public\\_repo\".\n\nЕсли у вашего токена нет необходимых областей объёмов или разрешений для access к ресурсу, API выдаст сообщение об ошибке с указанием области или разрешений, которые нужны вашему токену.\n\n### Аутентификация с помощью GitHub App\n\nЕсли вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендуется использовать GitHub App. Чтобы атрибутировать действие для приложения, можно выполнить проверку подлинности приложения в качестве установки приложения. Чтобы атрибутировать действие приложения пользователю, можно выполнить проверку подлинности приложения от имени пользователя. В обоих случаях вы создайте маркер, который можно использовать для проверки подлинности в API GraphQL. Для получения дополнительной информации см. [Регистрация приложения GitHub](/ru/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) и [Об аутентификации с помощью приложения GitHub](/ru/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).\n\n### Аутентификация с помощью OAuth app\n\nДля аутентификации с помощью токена OAuth OAuth appиз , сначала необходимо авторизировать OAuth app использование веб-приложения или device flow. Затем вы можете использовать полученный токен access для access к API. Для получения дополнительной информации см. [Создание приложения OAuth](/ru/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) и [Авторизация приложений OAuth](/ru/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps).\n\n## Конечная точка GraphQL\n\nREST API имеет множество конечных точек. С ПОМОЩЬЮ API GraphQL конечная точка остается постоянной, независимо от того, какая операция выполняется. Для GitHub.com, эта конечная точка выглядит:\n\n<pre>https://api.github.com/graphql</pre>\n\n## Взаимодействие с GraphQL\n\nПоскольку операции GraphQL состоят из многолинейного JSON, GitHub рекомендуется использовать [GraphQL Clients](/ru/graphql/guides/using-graphql-clients) для выполнения вызовов GraphQL. Вы также можете использовать `curl` или любую другую библиотеку HTTP-речи.\n\nВ REST [HTTP-команды](/ru/rest#http-verbs) определяют выполняемую операцию. В GraphQL вы предоставите текст в кодировке JSON независимо от того, выполняете ли вы запрос или изменение, поэтому HTTP-команда — `POST`. Исключение — запрос [интроспекционный](/ru/graphql/guides/introduction-to-graphql#discovering-the-graphql-api), который представляет собой простой `GET` к конечной точке. Для получения дополнительной информации о GraphQL и REST см. [Миграция из REST в GraphQL](/ru/graphql/guides/migrating-from-rest-to-graphql).\n\nЧтобы запросить GraphQL в команде `curl` , выполните `POST` запрос с полезными данными JSON. Полезные данные должны содержать строку `query`:\n\n```shell\ncurl -H \"Authorization: bearer TOKEN\" -X POST -d \" \\\n { \\\n   \\\"query\\\": \\\"query { viewer { login }}\\\" \\\n } \\\n\" https://api.github.com/graphql\n```\n\n> \\[!NOTE]\n> Строковое значение `\"query\"` должно экранировать символы новой строки или схема не будет правильно анализировать ее. Для текста запроса `POST` используйте внешние двойные кавычки и экранированные внутренние двойные кавычки.\n\n### Операции запроса и изменения\n\nДва типа разрешённых операций в API GraphQL GitHub — это *запросы* и *мутации*. Если сравнивать GraphQL с REST, запросы работают как запросы `GET`, а изменения — как `POST`/`PATCH`/`DELETE`. Имя мутации определяет, какая модификация будет выполнена.\n\nСведения об ограничении скорости см. в разделе [Ограничения скорости и ограничения запросов для API GraphQL](/ru/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api).\n\nЗапросы и изменения похожи по форме за несколькими важными различиями.\n\n### Сведения о запросах\n\nЗапросы GraphQL возвращают только указанные данные. Чтобы сформировать запрос, необходимо указать [поля внутри полей](/ru/graphql/guides/introduction-to-graphql#field) (также известных как *вложенные подполя*), пока не вернёте только скаляры.\n\nЗапросы имеют следующую структуру:\n\n<pre>query {\n  JSON-OBJECT-TO-RETURN\n}</pre>\n\nПример реального мира см. в разделе [\"Пример запроса](#example-query)\".\n\n### Сведения об изменениях\n\nЧтобы сформировать изменение, необходимо указать три элемента.\n\n1. *Имя изменения* — тип нужного изменения.\n2. *Входной объект* — данные, которые необходимо отправить на сервер; состоят из *полей входных данных*. Передайте его в качестве аргумента имени изменения.\n3. *Объект полезных данных* — данные, которые должны быть получены с сервера; состоят из *возвращаемых полей*. Передайте его в качестве тела имени мутации.\n\nИзменения имеют следующую структуру:\n\n<pre>mutation {\n  MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {\n    MUTATION-NAME-PAYLOAD\n  }\n}</pre>\n\nВходной объект в этом примере — `MutationNameInput`, а объект полезных данных — `MutationNamePayload`.\n\nВ ссылке на mutations указаны *поля входа* — это то, что вы передаёте как объект входа. Кроме того, перечислены *возвращаемые поля*, передаваемые в качестве объекта полезных данных.\n\nПример изменения в реальном мире см. в разделе [\"Пример изменения](#example-mutation)\".\n\n## Работа с переменными\n\n[Переменные](https://graphql.org/learn/queries/#variables) могут сделать запросы более динамичными и эффективными, снизив сложность при передаче входных объектов изменений.\n\nНиже приведен пример запроса с одной переменной.\n\n```graphql\nquery($number_of_repos:Int!) {\n  viewer {\n    name\n     repositories(last: $number_of_repos) {\n       nodes {\n         name\n       }\n     }\n   }\n}\nvariables {\n   \"number_of_repos\": 3\n}\n```\n\nПеременные используются в три этапа.\n\n1. Определите переменную вне операции в объекте `variables`:\n\n   ```graphql\n   variables {\n      \"number_of_repos\": 3\n   }\n   ```\n\n   Объект должен быть допустимым кодом JSON. В этом примере показана переменная простого типа `Int`, но можно определять переменные и более сложных типов, такие как входные объекты. Здесь также можно определить несколько переменных.\n\n2. Передайте переменную в операцию в качестве аргумента:\n\n   ```graphql\n   query($number_of_repos:Int!){\n   ```\n\n   Аргумент представляет собой пару \"ключ-значение\", где ключ — это *имя*, начинающееся с `$` (например, `$number_of_repos`), а значение — это *тип* (например, `Int`). Чтобы указать, что тип является обязательным, добавьте `!`. Если вы определили несколько переменных, включите их здесь как несколько аргументов.\n\n3. Используйте переменную в операции:\n\n   ```graphql\n   repositories(last: $number_of_repos) {\n   ```\n\n   В этом примере переменная означает количество получаемых репозиториев. Тип указывается на шаге 2, так как в GraphQL действует строгая типизация.\n\nЭтот процесс делает аргумент запроса динамическим. Теперь мы можем просто изменить значение в объекте `variables`, оставив остальную часть запроса без изменений.\n\nИспользование переменных в качестве аргументов позволяет динамически обновлять значения в объекте `variables`, не меняя запрос.\n\n## Пример запроса\n\nДавайте рассмотрим более сложный запрос в контексте.\n\nСледующий запрос обращается к репозиторию `octocat/Hello-World`, находит 20 последних закрытых проблем и возвращает заголовок, URL-адрес и первые пять меток каждой проблемы:\n\n```graphql\nquery {\n  repository(owner:\"octocat\", name:\"Hello-World\") {\n    issues(last:20, states:CLOSED) {\n      edges {\n        node {\n          title\n          url\n          labels(first:5) {\n            edges {\n              node {\n                name\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n```\n\nРассмотрим его структуру построчно.\n\n* `query {`\n\n  Так как мы хотим считать данные с сервера, а не изменить их, `query` является корневой операцией. (Если операция не указана, `query` также выполняется по умолчанию.)\n\n* `repository(owner:\"octocat\", name:\"Hello-World\") {`\n\n  Сначала нужно найти объект [`repository`](/ru/graphql/reference/repos#object-repository). Проверка схемы показывает, что для этого объекта требуются аргументы `owner` и `name`.\n\n* `issues(last:20, states:CLOSED) {`\n\n  Чтобы получить сведения о всех проблемах в репозитории, мы вызываем объект `issues`. (Мы *могли бы* запросить одну проблему `issue` из объекта `repository`, но для этого нужно знать количество возвращаемых проблем и предоставить его в качестве аргумента.)\n\n  Некоторые сведения об объекте `issues`:\n\n  * В [документации](/ru/graphql/reference/repos#object-repository) говорится, что этот объект имеет тип `IssueConnection`.\n  * Проверка схемы показывает, что в качестве аргумента для этого объекта требуется количество последних (`last`) или первых (`first`) результатов, поэтому мы указываем `20`.\n  * В [документах](/ru/graphql/reference/repos#object-repository) также говорится, что этот объект принимает `states` аргумент, который является `IssueState`[](/ru/graphql/reference/issues#enum-issuestate)перечислением, `OPEN` принимаюющим или `CLOSED` значениями. Чтобы найти только закрытые проблемы, мы присваиваем ключу `states` значение `CLOSED`.\n\n* `edges {`\n\n  Мы знаем, что объект `issues` — это соединение, так как он имеет тип `IssueConnection`. Чтобы получить данные по отдельным проблемам, нужно access узел через `edges`.\n\n* `node {`\n\n  В данном случае мы получаем узлы в конце ребра. В [документации по `IssueConnection`](/ru/graphql/reference/issues#object-issueconnection) указано, что узел в конце типа `IssueConnection` является объектом `Issue`.\n\n* Теперь, когда мы знаем, что извлекаем объект `Issue`, мы можем обратиться к [документации](/ru/graphql/reference/issues#object-issue) и указать поля, которые нужно вернуть:\n\n  ```graphql\n  title\n  url\n  labels(first:5) {\n    edges {\n      node {\n        name\n      }\n    }\n  }\n  ```\n\n  В данном случае мы указываем поля `title`, `url` и `labels` объекта `Issue`.\n\n  Тип поля `labels` — [`LabelConnection`](/ru/graphql/reference/issues#object-labelconnection). Как и в случае с объектом `issues`, так как `labels` — это соединение, необходимо пройти по его ребрам к подключенному узлу: объекту `label`. В этом узле можно указать поля объекта `label`, которые нужно вернуть, в данном случае `name`.\n\nВы можете заметить, что выполнение этого запроса в общедоступном `Hello-World` репозитории Octocat не возвращает много меток. Попробуйте выполнить его в одном из собственных репозиториев, использующих метки, и вы, скорее всего, заметите разницу.\n\n## Пример изменения\n\nДля изменений часто требуются сведения, которые можно узнать только путем предварительного выполнения запроса. В этом примере показаны две операции:\n\n1. запрос для получения идентификатора проблемы;\n2. изменение для добавления реакции эмодзи на проблему.\n\n```graphql\nquery FindIssueID {\n  repository(owner:\"octocat\", name:\"Hello-World\") {\n    issue(number:349) {\n      id\n    }\n  }\n}\n\nmutation AddReactionToIssue {\n  addReaction(input:{subjectId:\"MDU6SXNzdWUyMzEzOTE1NTE=\",content:HOORAY}) {\n    reaction {\n      content\n    }\n    subject {\n      id\n    }\n  }\n}\n```\n\nРазберем этот пример. Задача звучит просто: добавить реакцию эмодзи на проблему.\n\nС какого же запроса нам начать? Пока мы не знаем.\n\nТак как мы хотим изменить данные на сервере (добавить эмодзи к проблеме), мы начинаем с поиска подходящего изменения в схеме. В справочной документации есть изменение [`addReaction`](/ru/graphql/reference/reactions#mutation-addreaction) с таким описанием: `Adds a reaction to a subject.` Отлично!\n\nВ документации по изменению перечислены три поля входных данных:\n\n* `clientMutationId` (`String`)\n* `subjectId` (`ID!`)\n* `content` (`ReactionContent!`)\n\nСимволы `!` указывают, что `subjectId` и `content` являются обязательными полями. То, что поле `content` обязательное, разумно: мы хотим добавить реакцию, поэтому нам нужно указать, какой эмодзи следует использовать.\n\nНо почему обязательным является поле `subjectId`? Это связано с тем, что `subjectId` — это единственный способ указать, на *какую* проблему в *каком* репозитории следует отреагировать.\n\nВот почему мы начинаем этот пример с запроса: чтобы получить `ID`.\n\nДавайте разберем запрос построчно.\n\n* `query FindIssueID {`\n\n  Здесь мы выполняем запрос и называем его `FindIssueID`. Обратите внимание, что именование запроса является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента графического интерфейса, что и мутация.\n\n* `repository(owner:\"octocat\", name:\"Hello-World\") {`\n\n  Мы указываем репозиторий, запрашивая объект `repository` и передавая аргументы `owner` и `name`.\n\n* `issue(number:349) {`\n\n  Мы указываем проблему, на которую нужно отреагировать, запрашивая объект `issue` и передавая аргумент `number`.\n\n* `id`\n\n  Здесь мы получаем `id``https://github.com/octocat/Hello-World/issues/349`, чтобы пройти за `subjectId`.\n\nПри выполнении запроса мы получаем `id``MDU6SXNzdWUyMzEzOTE1NTE=`.\n\n> \\[!NOTE]\n> Возвращаемое `id` в запросе значение, которое мы передадим в виде `subjectID` изменения. Ни в документации, ни в схеме эта связь не определена. Необходимо просто понимать, как работают имена.\n\nЗная идентификатор, мы можем перейти к изменению:\n\n* `mutation AddReactionToIssue {`\n\n  Здесь мы выполняем изменение и называем его `AddReactionToIssue`. Как и в случае с запросами, именование мутации является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента с графическим интерфейсом, что и запрос.\n\n* `addReaction(input:{subjectId:\"MDU6SXNzdWUyMzEzOTE1NTE=\",content:HOORAY}) {`\n\n  Разберем эту строку:\n\n  * `addReaction` — это имя изменения.\n  * `input` — это обязательный ключ аргумента. Для изменения это всегда `input`.\n  * `{subjectId:\"MDU6SXNzdWUyMzEzOTE1NTE=\",content:HOORAY}` — это обязательное значение аргумента. Это всегда будет входной объект (отсюда и завитые скобки), состоящий из входных полей (`subjectId` и `content` в данном случае) для мутации.\n\n  Как узнать, какое значение следует использовать для содержимого?\n  [В`addReaction` документации](/ru/graphql/reference/reactions#mutation-addreaction) говорится, что в `content` поле есть тип [`ReactionContent`](/ru/graphql/reference/reactions#enum-reactioncontent), который является enum, потому что в GitHub поддерживаются только определённые эмодзи-реакции. Ниже перечислены допустимые значения для реакций (обратите внимание, что некоторые значения отличаются от соответствующих имен эмодзи).\n\n  <table style=\"width:20%\">\n  <thead>\n  <tr>\n  <th scope=\"col\" style=\"text-align:left\">Содержимое</th>\n  <th scope=\"col\" style=\"text-align:left\">Эмодзи</th>\n  </tr>\n  </thead>\n  <tbody>\n  <tr>\n  <td style=\"text-align:left\"><code>+1</code></td>\n  <td style=\"text-align:left\">👍</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>-1</code></td>\n  <td style=\"text-align:left\">👎</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>laugh</code></td>\n  <td style=\"text-align:left\">😄</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>confused</code></td>\n  <td style=\"text-align:left\">😕</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>heart</code></td>\n  <td style=\"text-align:left\">❤️</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>hooray</code></td>\n  <td style=\"text-align:left\">🎉</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>rocket</code></td>\n  <td style=\"text-align:left\">🚀</td>\n  </tr>\n  <tr>\n  <td style=\"text-align:left\"><code>eyes</code></td>\n  <td style=\"text-align:left\">👀</td>\n  </tr>\n  </tbody>\n  </table>\n\n* Остальная часть вызова — это объект полезных данных. Здесь мы указываем данные, которые сервер должен вернуть после изменения. В [документации по `addReaction`](/ru/graphql/reference/reactions#mutation-addreaction) определены три возможных возвращаемых поля:\n\n  * `clientMutationId` (`String`)\n  * `reaction` (`Reaction!`)\n  * `subject` (`Reactable!`)\n\n  В этом примере возвращаются два обязательных поля (`reaction` и `subject`); оба они имеют обязательные вложенные поля (`content` и `id` соответственно).\n\nПри выполнении изменения ответ будет следующим:\n\n```json\n{\n  \"data\": {\n    \"addReaction\": {\n      \"reaction\": {\n        \"content\": \"HOORAY\"\n      },\n      \"subject\": {\n        \"id\": \"MDU6SXNzdWUyMTc5NTQ0OTc=\"\n      }\n    }\n  }\n}\n```\n\nВот и все! Проверьте свою [reaction на проблему](https://github.com/octocat/Hello-World/issues/349) наведя курсор на :tada: чтобы найти своё имя пользователя.\n\nПоследнее замечание: при передаче нескольких полей во входном объекте синтаксис может получиться громоздким. Помочь может помещение полей в [переменную](#working-with-variables). Вот как можно переписать исходное изменение с использованием переменной:\n\n```graphql\nmutation($myVar:AddReactionInput!) {\n  addReaction(input:$myVar) {\n    reaction {\n      content\n    }\n    subject {\n      id\n    }\n  }\n}\nvariables {\n  \"myVar\": {\n    \"subjectId\":\"MDU6SXNzdWUyMTc5NTQ0OTc=\",\n    \"content\":\"HOORAY\"\n  }\n}\n```\n\n> \\[!NOTE]\n> Вы можете заметить, что в значении поля `content` в предыдущем примере (где оно используется в изменении напрямую) нет кавычек вокруг `HOORAY`, но при использовании в переменной кавычки есть. Этому есть причина:\n>\n> * При использовании `content` в изменении напрямую схема предполагает, что значение имеет тип [`ReactionContent`](/ru/graphql/reference/reactions#enum-reactioncontent), который является *перечислением*, а не строкой. Если добавить кавычки вокруг значения перечисления, при проверке схемы возникнет ошибка, так как кавычки зарезервированы для строк.\n> * При использовании `content` в переменной раздел переменных должен быть допустимым кодом JSON, поэтому кавычки требуются. Проверка схемы правильно интерпретирует тип `ReactionContent`, когда переменная передается в изменение во время выполнения.\n>\n> Дополнительные сведения о различиях между перечислениями и строками см. в [официальной спецификации GraphQL](https://spec.graphql.org/June2018/#sec-Enums).\n\n## Дополнительные материалы\n\nПри формировании вызовов GraphQL доступно *гораздо* больше возможностей. Дополнительную информацию можно найти в следующих ресурсах:\n\n* [автозаголовок](/ru/graphql/guides/using-pagination-in-the-graphql-api)\n* [Фрагменты](https://graphql.org/learn/queries/#fragments)\n* [Встроенные фрагменты](https://graphql.org/learn/queries/#inline-fragments)\n* [Директивы](https://graphql.org/learn/queries/#directives)"}