Проверка подлинности с помощью GraphQL
Вы можете пройти проверку подлинности в API GraphQL с помощью personal access token, GitHub Appили OAuth app.
Проверка подлинности с помощью personal access token
Для аутентификации с помощью personal access token выполните шаги, указанные в Управление личными маркерами доступа. Запрашиваемые данные определяют, какие области или разрешения потребуются.
Например, выберите разрешение "issues:read", чтобы прочитать все проблемы в репозиториях, к которым ваш токен имеет access.
Все fine-grained personal access token включают чтение access в публичные репозитории. Чтобы access публичные репозитории с personal access token (classic), выберите область действия "public_repo".
Если у вашего токена нет необходимых областей объёмов или разрешений для access к ресурсу, API выдаст сообщение об ошибке с указанием области или разрешений, которые нужны вашему токену.
Проверка подлинности с помощью GitHub App
Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендует использовать GitHub App. Чтобы атрибутировать действие для приложения, можно выполнить проверку подлинности приложения в качестве установки приложения. Чтобы атрибутировать действие приложения пользователю, можно выполнить проверку подлинности приложения от имени пользователя. В обоих случаях вы создайте маркер, который можно использовать для проверки подлинности в API GraphQL. Для получения дополнительной информации см. Регистрация приложения GitHub и Об аутентификации с помощью приложения GitHub.
Проверка подлинности с помощью OAuth app
Чтобы выполнить проверку подлинности с помощью маркера OAuth из OAuth app, необходимо сначала авторизовать OAuth app с помощью потока веб-приложения или потока устройства. Затем вы можете использовать полученный токен access для access к API. Дополнительные сведения см. в разделе [AUTOTITLE и Создание приложения OAuth](/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps).
Конечная точка GraphQL
REST API имеет множество конечных точек. С ПОМОЩЬЮ API GraphQL конечная точка остается постоянной, независимо от того, какая операция выполняется. Для GitHub Enterprise Server, эта конечная точка:
http(s)://HOSTNAME/api/graphql
Взаимодействие с GraphQL
Поскольку операции GraphQL состоят из многолинейного JSON, GitHub рекомендуется использовать GraphQL Clients для выполнения вызовов GraphQL. Вы также можете использовать curl или любую другую библиотеку HTTP-речи.
В REST HTTP-команды определяют выполняемую операцию. В GraphQL вы предоставите текст в кодировке JSON независимо от того, выполняете ли вы запрос или изменение, поэтому HTTP-команда — POST. Исключение — запрос интроспекционный, который представляет собой простой GET к конечной точке. Для получения дополнительной информации о GraphQL и REST см. Миграция из REST в GraphQL.
Чтобы запросить GraphQL в команде curl , выполните POST запрос с полезными данными JSON. Полезные данные должны содержать строку query:
curl -H "Authorization: bearer TOKEN" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" http(s)://HOSTNAME/api/graphql
Примечание.
Строковое значение "query" должно экранировать символы новой строки или схема не будет правильно анализировать ее. Для текста запроса POST используйте внешние двойные кавычки и экранированные внутренние двойные кавычки.
Операции запроса и изменения
Два типа разрешённых операций в API GraphQL GitHub — это запросы и мутации. Если сравнивать GraphQL с REST, запросы работают как запросы GET, а изменения — как POST/PATCH/DELETE.
Имя изменения определяет производимую модификацию.
Сведения об ограничении скорости см. в разделе Ограничения скорости и ограничения запросов для API GraphQL.
Запросы и изменения похожи по форме за несколькими важными различиями.
Сведения о запросах
Запросы GraphQL возвращают только указанные данные. Для формирования запроса необходимо указать поля внутри полей (также известных как вложенные подполя), пока не вернётся только скаляры.
Запросы имеют следующую структуру:
query {
JSON-OBJECT-TO-RETURN
}
Пример реального мира см. в разделе "Пример запроса".
Сведения об изменениях
Чтобы сформировать изменение, необходимо указать три элемента.
-
_Имя изменения_ — тип нужного изменения. -
_Входной объект_ — данные, которые необходимо отправить на сервер; состоят из _полей входных данных_. Передайте его в качестве аргумента имени изменения. -
_Объект полезных данных_ — данные, которые должны быть получены с сервера; состоят из _возвращаемых полей_. Передайте его в качестве тела имени мутации.
Изменения имеют следующую структуру:
mutation {
MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
MUTATION-NAME-PAYLOAD
}
}
Входной объект в этом примере — MutationNameInput, а объект полезных данных — MutationNamePayload.
В справочнике по изменениям перечислены поля входных данных, передаваемые в качестве входного объекта. Кроме того, перечислены возвращаемые поля, передаваемые в качестве объекта полезных данных.
Пример изменения в реальном мире см. в разделе "Пример изменения".
Работа с переменными
[Переменные](https://graphql.org/learn/queries/#variables) могут сделать запросы более динамичными и эффективными, снизив сложность при передаче входных объектов изменений.
Ниже приведен пример запроса с одной переменной.
query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}
variables {
"number_of_repos": 3
}
Переменные используются в три этапа.
-
Определите переменную вне операции в объекте
variables:variables { "number_of_repos": 3 }Объект должен быть допустимым кодом JSON. В этом примере показана переменная простого типа
Int, но можно определять переменные и более сложных типов, такие как входные объекты. Здесь также можно определить несколько переменных. -
Передайте переменную в операцию в качестве аргумента:
query($number_of_repos:Int!){Аргумент представляет собой пару "ключ-значение", где ключ — это имя, начинающееся с
$(например,$number_of_repos), а значение — это тип (например,Int). Чтобы указать, что тип является обязательным, добавьте!. Если вы определили несколько переменных, включите их здесь как несколько аргументов. -
Используйте переменную в операции:
repositories(last: $number_of_repos) {В этом примере переменная означает количество получаемых репозиториев. Тип указывается на шаге 2, так как в GraphQL действует строгая типизация.
Этот процесс делает аргумент запроса динамическим. Теперь мы можем просто изменить значение в объекте variables, оставив остальную часть запроса без изменений.
Использование переменных в качестве аргументов позволяет динамически обновлять значения в объекте variables, не меняя запрос.
Пример запроса
Давайте рассмотрим более сложный запрос в контексте.
Следующий запрос обращается к репозиторию octocat/Hello-World, находит 20 последних закрытых проблем и возвращает заголовок, URL-адрес и первые пять меток каждой проблемы:
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. Проверка схемы показывает, что для этого объекта требуются аргументыownerиname. -
issues(last:20, states:CLOSED) {Чтобы получить сведения о всех проблемах в репозитории, мы вызываем объект
issues. (Мы могли бы запросить одну проблемуissueиз объектаrepository, но для этого нужно знать количество возвращаемых проблем и предоставить его в качестве аргумента.)Некоторые сведения об объекте
issues:- В документации говорится, что этот объект имеет тип
IssueConnection. - Проверка схемы показывает, что в качестве аргумента для этого объекта требуется количество последних (
last) или первых (first) результатов, поэтому мы указываем20. - В документах также говорится, что этот объект принимает
statesаргумент, который являетсяIssueStateперечислением,OPENпринимаюющим илиCLOSEDзначениями. Чтобы найти только закрытые проблемы, мы присваиваем ключуstatesзначениеCLOSED.
- В документации говорится, что этот объект имеет тип
-
edges {Мы знаем, что объект
issues— это соединение, так как он имеет типIssueConnection. Чтобы получить данные по отдельным проблемам, нужно access узел черезedges. -
node {В данном случае мы получаем узлы в конце ребра. В документации по
IssueConnectionуказано, что узел в конце типаIssueConnectionявляется объектомIssue. -
Теперь, когда мы знаем, что извлекаем объект
Issue, мы можем обратиться к документации и указать поля, которые нужно вернуть:title url labels(first:5) { edges { node { name } } }В данном случае мы указываем поля
title,urlиlabelsобъектаIssue.Тип поля
labels—LabelConnection. Как и в случае с объектомissues, так какlabels— это соединение, необходимо пройти по его ребрам к подключенному узлу: объектуlabel. В этом узле можно указать поля объектаlabel, которые нужно вернуть, в данном случаеname.
Вы можете заметить, что выполнение этого запроса в общедоступном Hello-World репозитории Octocat не возвращает много меток. Попробуйте выполнить его в одном из собственных репозиториев, использующих метки, и вы, скорее всего, заметите разницу.
Пример изменения
Для изменений часто требуются сведения, которые можно узнать только путем предварительного выполнения запроса. В этом примере показаны две операции:
- запрос для получения идентификатора проблемы;
- изменение для добавления реакции эмодзи на проблему.
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 с таким описанием: 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=.
Примечание.
Возвращаемое id в запросе значение, которое мы передадим в виде subjectID изменения. Ни в документации, ни в схеме эта связь не определена. Необходимо просто понимать, как работают имена.
Зная идентификатор, мы можем перейти к изменению:
-
mutation AddReactionToIssue {Здесь мы выполняем изменение и называем его
AddReactionToIssue. Как и в случае с запросами, именование мутации является необязательным; мы даем ему имя здесь, чтобы мы могли включить его в то же окно клиента с графическим интерфейсом, что и запрос. -
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {Разберем эту строку:
-
`addReaction` — это имя изменения. -
`input` — это обязательный ключ аргумента. Для изменения это всегда `input`. -
`{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}` — это обязательное значение аргумента. Для изменения это всегда будет [входной объект](/graphql/reference/input-objects) (отсюда фигурные скобки), состоящий из полей входных данных (в данном случае `subjectId` и `content`).
Как узнать, какое значение следует использовать для содержимого? Документы
addReactionсообщают, что полеcontentимеет типReactionContent, который является enum потому что по GitHub вопросам поддерживаются только определённые эмодзи. Ниже перечислены допустимые значения для реакций (обратите внимание, что некоторые значения отличаются от соответствующих имен эмодзи).Содержимое Эмодзи +1👍 -1👎 laugh😄 confused😕 heart❤️ hooray🎉 rocket🚀 eyes👀 -
-
Остальная часть вызова — это объект полезных данных. Здесь мы указываем данные, которые сервер должен вернуть после изменения. В документации по
addReactionопределены три возможных возвращаемых поля:-
`clientMutationId` (`String`) -
`reaction` (`Reaction!`) -
`subject` (`Reactable!`)
В этом примере возвращаются два обязательных поля (
reactionиsubject); оба они имеют обязательные вложенные поля (contentиidсоответственно). -
При выполнении изменения ответ будет следующим:
{
"data": {
"addReaction": {
"reaction": {
"content": "HOORAY"
},
"subject": {
"id": "MDU6SXNzdWUyMTc5NTQ0OTc="
}
}
}
}
Вот и все! Проверьте свою reaction на проблему наведя курсор на 🎉 чтобы найти своё имя пользователя.
Последнее замечание: при передаче нескольких полей во входном объекте синтаксис может получиться громоздким. Помочь может помещение полей в переменную. Вот как можно переписать исходное изменение с использованием переменной:
mutation($myVar:AddReactionInput!) {
addReaction(input:$myVar) {
reaction {
content
}
subject {
id
}
}
}
variables {
"myVar": {
"subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
"content":"HOORAY"
}
}
Примечание.
Вы можете заметить, что в значении поля content в предыдущем примере (где оно используется в изменении напрямую) нет кавычек вокруг HOORAY, но при использовании в переменной кавычки есть. Этому есть причина:
- При использовании
contentв изменении напрямую схема предполагает, что значение имеет типReactionContent, который является перечислением, а не строкой. Если добавить кавычки вокруг значения перечисления, при проверке схемы возникнет ошибка, так как кавычки зарезервированы для строк. - При использовании
contentв переменной раздел переменных должен быть допустимым кодом JSON, поэтому кавычки требуются. Проверка схемы правильно интерпретирует типReactionContent, когда переменная передается в изменение во время выполнения.
Дополнительные сведения о различиях между перечислениями и строками см. в официальной спецификации GraphQL.
Дополнительные материалы
При формировании вызовов GraphQL доступно гораздо больше возможностей. Дополнительную информацию можно найти в следующих ресурсах:
-
[автозаголовок](/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)