# Формирование вызовов с помощью GraphQL

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

## Проверка подлинности с помощью GraphQL

Вы можете аутентифицироваться в API GraphQL с помощью personal access token, GitHub App, или OAuth app.

### Аутентификация с помощью personal access token

Для аутентификации personal access tokenс помощью , следуйте шагам в [Управление личными маркерами доступа](/ru/enterprise-server@3.22/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens). Запрашиваемые данные определяют, какие области или разрешения потребуются.

Например, выберите разрешение "issues:read", чтобы прочитать все проблемы в репозиториях, к которым ваш токен имеет access.

Все fine-grained personal access tokens имеют доступ к публичным репозиториям. Чтобы получить доступ к публичным репозиториям с personal access token (classic)помощью , выберите область действия "public\_repo".

Если у вашего токена нет необходимых областей объёмов или разрешений для access к ресурсу, API выдаст сообщение об ошибке с указанием области или разрешений, которые нужны вашему токену.

### Аутентификация с помощью GitHub App

Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендуется использовать GitHub App. Чтобы атрибутировать действие для приложения, можно выполнить проверку подлинности приложения в качестве установки приложения. Чтобы атрибутировать действие приложения пользователю, можно выполнить проверку подлинности приложения от имени пользователя. В обоих случаях вы создайте маркер, который можно использовать для проверки подлинности в API GraphQL. Для получения дополнительной информации см. [Регистрация приложения GitHub](/ru/enterprise-server@3.22/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) и [Об аутентификации с помощью приложения GitHub](/ru/enterprise-server@3.22/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).

### Аутентификация с помощью OAuth app

Для аутентификации с помощью токена OAuth OAuth appиз , сначала необходимо авторизировать OAuth app использование веб-приложения или device flow. Затем вы можете использовать полученный токен access для access к API. Для получения дополнительной информации см. [Создание приложения OAuth](/ru/enterprise-server@3.22/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) и [Авторизация приложений OAuth](/ru/enterprise-server@3.22/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps).

## Конечная точка GraphQL

REST API имеет множество конечных точек. С ПОМОЩЬЮ API GraphQL конечная точка остается постоянной, независимо от того, какая операция выполняется. Для GitHub Enterprise Server, эта конечная точка выглядит:

<pre>http(s)://HOSTNAME/api/graphql</pre>

## Взаимодействие с GraphQL

Поскольку операции GraphQL состоят из многолинейного JSON, GitHub рекомендуется использовать [GraphQL Clients](/ru/enterprise-server@3.22/graphql/guides/using-graphql-clients) для выполнения вызовов GraphQL. Вы также можете использовать `curl` или любую другую библиотеку HTTP-речи.

В REST [HTTP-команды](/ru/enterprise-server@3.22/rest#http-verbs) определяют выполняемую операцию. В GraphQL вы предоставите текст в кодировке JSON независимо от того, выполняете ли вы запрос или изменение, поэтому HTTP-команда — `POST`. Исключение — запрос [интроспекционный](/ru/enterprise-server@3.22/graphql/guides/introduction-to-graphql#discovering-the-graphql-api), который представляет собой простой `GET` к конечной точке. Для получения дополнительной информации о GraphQL и REST см. [Миграция из REST в GraphQL](/ru/enterprise-server@3.22/graphql/guides/migrating-from-rest-to-graphql).

Чтобы запросить GraphQL в команде `curl` , выполните `POST` запрос с полезными данными JSON. Полезные данные должны содержать строку `query`:

```shell
curl -H "Authorization: bearer TOKEN" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
" http(s)://HOSTNAME/api/graphql
```

> \[!NOTE]
> Строковое значение `"query"` должно экранировать символы новой строки или схема не будет правильно анализировать ее. Для текста запроса `POST` используйте внешние двойные кавычки и экранированные внутренние двойные кавычки.

### Операции запроса и изменения

Два типа разрешённых операций в API GraphQL GitHub — это *запросы* и *мутации*. Если сравнивать GraphQL с REST, запросы работают как запросы `GET`, а изменения — как `POST`/`PATCH`/`DELETE`. Имя мутации определяет, какая модификация будет выполнена.

Сведения об ограничении скорости см. в разделе [Ограничения скорости и ограничения запросов для API GraphQL](/ru/enterprise-server@3.22/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api).

Запросы и изменения похожи по форме за несколькими важными различиями.

### Сведения о запросах

Запросы GraphQL возвращают только указанные данные. Чтобы сформировать запрос, необходимо указать [поля внутри полей](/ru/enterprise-server@3.22/graphql/guides/introduction-to-graphql#field) (также известных как *вложенные подполя*), пока не вернёте только скаляры.

Запросы имеют следующую структуру:

<pre>query {
  JSON-OBJECT-TO-RETURN
}</pre>

Пример реального мира см. в разделе ["Пример запроса](#example-query)".

### Сведения об изменениях

Чтобы сформировать изменение, необходимо указать три элемента.

1. *Имя изменения* — тип нужного изменения.
2. *Входной объект* — данные, которые необходимо отправить на сервер; состоят из *полей входных данных*. Передайте его в качестве аргумента имени изменения.
3. *Объект полезных данных* — данные, которые должны быть получены с сервера; состоят из *возвращаемых полей*. Передайте его в качестве тела имени мутации.

Изменения имеют следующую структуру:

<pre>mutation {
  MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
    MUTATION-NAME-PAYLOAD
  }
}</pre>

Входной объект в этом примере — `MutationNameInput`, а объект полезных данных — `MutationNamePayload`.

В ссылке на mutations указаны *поля входа* — это то, что вы передаёте как объект входа. Кроме того, перечислены *возвращаемые поля*, передаваемые в качестве объекта полезных данных.

Пример изменения в реальном мире см. в разделе ["Пример изменения](#example-mutation)".

## Работа с переменными

[Переменные](https://graphql.org/learn/queries/#variables) могут сделать запросы более динамичными и эффективными, снизив сложность при передаче входных объектов изменений.

Ниже приведен пример запроса с одной переменной.

```graphql
query($number_of_repos:Int!) {
  viewer {
    name
     repositories(last: $number_of_repos) {
       nodes {
         name
       }
     }
   }
}
variables {
   "number_of_repos": 3
}
```

Переменные используются в три этапа.

1. Определите переменную вне операции в объекте `variables`:

   ```graphql
   variables {
      "number_of_repos": 3
   }
   ```

   Объект должен быть допустимым кодом JSON. В этом примере показана переменная простого типа `Int`, но можно определять переменные и более сложных типов, такие как входные объекты. Здесь также можно определить несколько переменных.

2. Передайте переменную в операцию в качестве аргумента:

   ```graphql
   query($number_of_repos:Int!){
   ```

   Аргумент представляет собой пару "ключ-значение", где ключ — это *имя*, начинающееся с `$` (например, `$number_of_repos`), а значение — это *тип* (например, `Int`). Чтобы указать, что тип является обязательным, добавьте `!`. Если вы определили несколько переменных, включите их здесь как несколько аргументов.

3. Используйте переменную в операции:

   ```graphql
   repositories(last: $number_of_repos) {
   ```

   В этом примере переменная означает количество получаемых репозиториев. Тип указывается на шаге 2, так как в GraphQL действует строгая типизация.

Этот процесс делает аргумент запроса динамическим. Теперь мы можем просто изменить значение в объекте `variables`, оставив остальную часть запроса без изменений.

Использование переменных в качестве аргументов позволяет динамически обновлять значения в объекте `variables`, не меняя запрос.

## Пример запроса

Давайте рассмотрим более сложный запрос в контексте.

Следующий запрос обращается к репозиторию `octocat/Hello-World`, находит 20 последних закрытых проблем и возвращает заголовок, URL-адрес и первые пять меток каждой проблемы:

```graphql
query {
  repository(owner:"octocat", name:"Hello-World") {
    issues(last:20, states:CLOSED) {
      edges {
        node {
          title
          url
          labels(first:5) {
            edges {
              node {
                name
              }
            }
          }
        }
      }
    }
  }
}
```

Рассмотрим его структуру построчно.

* `query {`

  Так как мы хотим считать данные с сервера, а не изменить их, `query` является корневой операцией. (Если операция не указана, `query` также выполняется по умолчанию.)

* `repository(owner:"octocat", name:"Hello-World") {`

  Сначала нужно найти объект [`repository`](/ru/enterprise-server@3.22/graphql/reference/repos#object-repository). Проверка схемы показывает, что для этого объекта требуются аргументы `owner` и `name`.

* `issues(last:20, states:CLOSED) {`

  Чтобы получить сведения о всех проблемах в репозитории, мы вызываем объект `issues`. (Мы *могли бы* запросить одну проблему `issue` из объекта `repository`, но для этого нужно знать количество возвращаемых проблем и предоставить его в качестве аргумента.)

  Некоторые сведения об объекте `issues`:

  * В [документации](/ru/enterprise-server@3.22/graphql/reference/repos#object-repository) говорится, что этот объект имеет тип `IssueConnection`.
  * Проверка схемы показывает, что в качестве аргумента для этого объекта требуется количество последних (`last`) или первых (`first`) результатов, поэтому мы указываем `20`.
  * В [документах](/ru/enterprise-server@3.22/graphql/reference/repos#object-repository) также говорится, что этот объект принимает `states` аргумент, который является `IssueState`[](/ru/enterprise-server@3.22/graphql/reference/issues#enum-issuestate)перечислением, `OPEN` принимаюющим или `CLOSED` значениями. Чтобы найти только закрытые проблемы, мы присваиваем ключу `states` значение `CLOSED`.

* `edges {`

  Мы знаем, что объект `issues` — это соединение, так как он имеет тип `IssueConnection`. Чтобы получить данные по отдельным проблемам, нужно access узел через `edges`.

* `node {`

  В данном случае мы получаем узлы в конце ребра. В [документации по `IssueConnection`](/ru/enterprise-server@3.22/graphql/reference/issues#object-issueconnection) указано, что узел в конце типа `IssueConnection` является объектом `Issue`.

* Теперь, когда мы знаем, что извлекаем объект `Issue`, мы можем обратиться к [документации](/ru/enterprise-server@3.22/graphql/reference/issues#object-issue) и указать поля, которые нужно вернуть:

  ```graphql
  title
  url
  labels(first:5) {
    edges {
      node {
        name
      }
    }
  }
  ```

  В данном случае мы указываем поля `title`, `url` и `labels` объекта `Issue`.

  Тип поля `labels` — [`LabelConnection`](/ru/enterprise-server@3.22/graphql/reference/issues#object-labelconnection). Как и в случае с объектом `issues`, так как `labels` — это соединение, необходимо пройти по его ребрам к подключенному узлу: объекту `label`. В этом узле можно указать поля объекта `label`, которые нужно вернуть, в данном случае `name`.

Вы можете заметить, что выполнение этого запроса в общедоступном `Hello-World` репозитории Octocat не возвращает много меток. Попробуйте выполнить его в одном из собственных репозиториев, использующих метки, и вы, скорее всего, заметите разницу.

## Пример изменения

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

1. запрос для получения идентификатора проблемы;
2. изменение для добавления реакции эмодзи на проблему.

```graphql
query FindIssueID {
  repository(owner:"octocat", name:"Hello-World") {
    issue(number:349) {
      id
    }
  }
}

mutation AddReactionToIssue {
  addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}
```

Разберем этот пример. Задача звучит просто: добавить реакцию эмодзи на проблему.

С какого же запроса нам начать? Пока мы не знаем.

Так как мы хотим изменить данные на сервере (добавить эмодзи к проблеме), мы начинаем с поиска подходящего изменения в схеме. В справочной документации есть изменение [`addReaction`](/ru/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction) с таким описанием: `Adds a reaction to a subject.` Отлично!

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

* `clientMutationId` (`String`)
* `subjectId` (`ID!`)
* `content` (`ReactionContent!`)

Символы `!` указывают, что `subjectId` и `content` являются обязательными полями. То, что поле `content` обязательное, разумно: мы хотим добавить реакцию, поэтому нам нужно указать, какой эмодзи следует использовать.

Но почему обязательным является поле `subjectId`? Это связано с тем, что `subjectId` — это единственный способ указать, на *какую* проблему в *каком* репозитории следует отреагировать.

Вот почему мы начинаем этот пример с запроса: чтобы получить `ID`.

Давайте разберем запрос построчно.

* `query FindIssueID {`

  Здесь мы выполняем запрос и называем его `FindIssueID`. Обратите внимание, что именование запроса является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента графического интерфейса, что и мутация.

* `repository(owner:"octocat", name:"Hello-World") {`

  Мы указываем репозиторий, запрашивая объект `repository` и передавая аргументы `owner` и `name`.

* `issue(number:349) {`

  Мы указываем проблему, на которую нужно отреагировать, запрашивая объект `issue` и передавая аргумент `number`.

* `id`

  Здесь мы получаем `id``https://github.com/octocat/Hello-World/issues/349`, чтобы пройти за `subjectId`.

При выполнении запроса мы получаем `id``MDU6SXNzdWUyMzEzOTE1NTE=`.

> \[!NOTE]
> Возвращаемое `id` в запросе значение, которое мы передадим в виде `subjectID` изменения. Ни в документации, ни в схеме эта связь не определена. Необходимо просто понимать, как работают имена.

Зная идентификатор, мы можем перейти к изменению:

* `mutation AddReactionToIssue {`

  Здесь мы выполняем изменение и называем его `AddReactionToIssue`. Как и в случае с запросами, именование мутации является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента с графическим интерфейсом, что и запрос.

* `addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {`

  Разберем эту строку:

  * `addReaction` — это имя изменения.
  * `input` — это обязательный ключ аргумента. Для изменения это всегда `input`.
  * `{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}` — это обязательное значение аргумента. Это всегда будет входной объект (отсюда и завитые скобки), состоящий из входных полей (`subjectId` и `content` в данном случае) для мутации.

  Как узнать, какое значение следует использовать для содержимого?
  [В`addReaction` документации](/ru/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction) говорится, что в `content` поле есть тип [`ReactionContent`](/ru/enterprise-server@3.22/graphql/reference/reactions#enum-reactioncontent), который является enum, потому что в GitHub поддерживаются только определённые эмодзи-реакции. Ниже перечислены допустимые значения для реакций (обратите внимание, что некоторые значения отличаются от соответствующих имен эмодзи).

  <table style="width:20%">
  <thead>
  <tr>
  <th scope="col" style="text-align:left">Содержимое</th>
  <th scope="col" style="text-align:left">Эмодзи</th>
  </tr>
  </thead>
  <tbody>
  <tr>
  <td style="text-align:left"><code>+1</code></td>
  <td style="text-align:left">👍</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>-1</code></td>
  <td style="text-align:left">👎</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>laugh</code></td>
  <td style="text-align:left">😄</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>confused</code></td>
  <td style="text-align:left">😕</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>heart</code></td>
  <td style="text-align:left">❤️</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>hooray</code></td>
  <td style="text-align:left">🎉</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>rocket</code></td>
  <td style="text-align:left">🚀</td>
  </tr>
  <tr>
  <td style="text-align:left"><code>eyes</code></td>
  <td style="text-align:left">👀</td>
  </tr>
  </tbody>
  </table>

* Остальная часть вызова — это объект полезных данных. Здесь мы указываем данные, которые сервер должен вернуть после изменения. В [документации по `addReaction`](/ru/enterprise-server@3.22/graphql/reference/reactions#mutation-addreaction) определены три возможных возвращаемых поля:

  * `clientMutationId` (`String`)
  * `reaction` (`Reaction!`)
  * `subject` (`Reactable!`)

  В этом примере возвращаются два обязательных поля (`reaction` и `subject`); оба они имеют обязательные вложенные поля (`content` и `id` соответственно).

При выполнении изменения ответ будет следующим:

```json
{
  "data": {
    "addReaction": {
      "reaction": {
        "content": "HOORAY"
      },
      "subject": {
        "id": "MDU6SXNzdWUyMTc5NTQ0OTc="
      }
    }
  }
}
```

Вот и все! Проверьте свою [reaction на проблему](https://github.com/octocat/Hello-World/issues/349) наведя курсор на :tada: чтобы найти своё имя пользователя.

Последнее замечание: при передаче нескольких полей во входном объекте синтаксис может получиться громоздким. Помочь может помещение полей в [переменную](#working-with-variables). Вот как можно переписать исходное изменение с использованием переменной:

```graphql
mutation($myVar:AddReactionInput!) {
  addReaction(input:$myVar) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}
variables {
  "myVar": {
    "subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
    "content":"HOORAY"
  }
}
```

> \[!NOTE]
> Вы можете заметить, что в значении поля `content` в предыдущем примере (где оно используется в изменении напрямую) нет кавычек вокруг `HOORAY`, но при использовании в переменной кавычки есть. Этому есть причина:
>
> * При использовании `content` в изменении напрямую схема предполагает, что значение имеет тип [`ReactionContent`](/ru/enterprise-server@3.22/graphql/reference/reactions#enum-reactioncontent), который является *перечислением*, а не строкой. Если добавить кавычки вокруг значения перечисления, при проверке схемы возникнет ошибка, так как кавычки зарезервированы для строк.
> * При использовании `content` в переменной раздел переменных должен быть допустимым кодом JSON, поэтому кавычки требуются. Проверка схемы правильно интерпретирует тип `ReactionContent`, когда переменная передается в изменение во время выполнения.
>
> Дополнительные сведения о различиях между перечислениями и строками см. в [официальной спецификации GraphQL](https://spec.graphql.org/June2018/#sec-Enums).

## Дополнительные материалы

При формировании вызовов GraphQL доступно *гораздо* больше возможностей. Дополнительную информацию можно найти в следующих ресурсах:

* [автозаголовок](/ru/enterprise-server@3.22/graphql/guides/using-pagination-in-the-graphql-api)
* [Фрагменты](https://graphql.org/learn/queries/#fragments)
* [Встроенные фрагменты](https://graphql.org/learn/queries/#inline-fragments)
* [Директивы](https://graphql.org/learn/queries/#directives)